Note that when using a thread pool to refuse pit strategy

Reprinted from:
http://ifeve.com/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BD%BF%E7%94%A8futuretask%E6%97%B6%E5% 80% 99% E9% 9C% 80% E8% A6% 81% E6% B3% A8% E6% 84% 8F% E7% 9A% 84% E4% B8% 80% E7% 82% B9% E4% BA% 8B /

  FutureTask when using the thread pool policy settings if refuse to DiscardPolicy and DiscardOldestPolicy and call the method with no arguments get on the Future of the object is rejected then the task of the calling thread will always be blocked.

Recurring problem

    public static void main(String[] args) throws Exception {

        //(1)线程池单个线程,线程池队列元素个数为1
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(1, 1,
                1L, TimeUnit.MINUTES,
                new ArrayBlockingQueue<>(1),
                new ThreadPoolExecutor.DiscardPolicy());

        //(2)添加任务one
        Future futureOne = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("start runable one");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //(3)添加任务two
        Future futureTwo = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("start runable two");
            }
        });

        //(4)添加任务three
        Future futureThree = null;
        try {
            futureThree = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("start runable three");
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getLocalizedMessage());
        }

        System.out.println("task one finish " + futureOne.get());//(5)等待任务one执行完毕
        System.out.println("task two finish " + futureTwo.get());//(6)等待任务two执行完毕
        System.out.println("task three finish " + (futureThree == null ? null : futureThree.get()));// (7)等待任务three执行完毕

        executorService.shutdown();//(8)关闭线程池,阻塞直到所有任务执行完毕
    }
   
   

  operation result:

start runable one
task one finish null
start runable two
task two finish null
   
   

  Created a single-threaded and the number of elements in the queue for the thread pool 1, and reject the policy settings for DiscardPolicy; to submit a task one, this task will use only one thread to perform the task after printing start runable one can block the thread 5s; again submitted a thread pool task two, this time will put to task two blocking queue; when submitting mission three, refused to discard the policy task three because the queue is full is triggered.
  Looking at the results from running in one task blocked 5s, the main thread to execute the code (5) one waiting task is finished, when one task is finished the code (5) returns, the main thread prints out task one finish null. After the only thread in the thread pool would go queue inside the Fetch Task two and perform the output start runable two and the code (6) is returned, this time the main thread output task two finish null, then execution of the code (7) waiting task three finished, look at the code (7) the result would have been blocked from execution does not return.
  So far problems, if the refusal to amend the policy DiscardOldestPolicy there will have a task get method blocks until the task is now just two blocked:

start runable one
task one finish null
start runable three
   
   

  However, if the policy is set to reject the default AbortPolicy will throw RejectedExecutionException and return to normal.

problem analysis

  To analyze this issue needs to look inside the submit method thread pool did what, submit method code is as follows:

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
   
   

  newTaskFor () Runnable into the FutureTask objects, FutureTask achieve RunnableFuture interfaces, continue with execute:

public void execute(Runnable command) {
        // ...
        // 如果线程个数消息核心线程数则新增处理线程处理
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 如果当前线程个数已经达到核心线程数则任务放入队列
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 尝试新增处理线程进行处理
        else if (!addWorker(command, false))
            reject(command);// 新增失败则调用拒绝策略
    }
    final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }
   
   

  Then look at the rejected policy DiscardPolicy code:

    public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
   
   

  Here inside rejectedExecution method did not do anything, so the code (4) after a call to submit returns a future object, that FutureTask:

public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * Possible state transitions:
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;
   
   

  FutureTask state state identification, the initial state New. Therefore, after use DiscardPolicy strategy submitted returns a status of NEW FutureTask objects.
  Then the following will need to look no arguments when calling the get method of the future when the future time when it will return to state why the change:

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)  // 状态值为NORMAL正常返回
            return (V)x;
        if (s >= CANCELLED) // 状态值大于等于CANCELLED则抛异常
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }
   
   

  That is when the future status> COMPLETING when calling the get method will return, but obviously DiscardPolicy policy and the state of the future is not set at the time rejected elements, there is no other opportunities later in the future state can be set, so the future of the state It has been the NEW, so they will not return, empathy DiscardOldestPolicy strategy is such a problem, the oldest task to be eliminated when there is no task for the future is set to be out of state, will lead to has not returned.
  So why did not the default AbortPolicy policy issues that? View AbortPolicy policy code:

    public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
   
   

  Look at the code should get the idea.

  So when using the Future, try to use the get method with a timeout, so even with DiscardPolicy deny policy will not have been waiting, waiting for the timeout time is up, if you have to use the get method with no parameters will automatically return you can rewriting DiscardPolicy deny policy setting in the Future state when execution policy can be greater than COMPLETING, see the methods provided FutureTask found only cancel method is public and can be set larger than COMPLETING FutureTask state, the specific code rewriting deny policy may be as follows :

    public static void main(String[] args) throws Exception {
        //(1)线程池单个线程,线程池队列元素个数为1
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(1, 1,
                1L, TimeUnit.MINUTES,
                new ArrayBlockingQueue<>(1),
                new ThreadPoolExecutor.DiscardPolicy() {
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                        if (!e.isShutdown()) {
                            if (r != null && r instanceof FutureTask) {
                                ((FutureTask) r).cancel(true);
                            }
                        }
                    }
                }
        );

        //(2)添加任务one
        Future futureOne = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("start runable one");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //(3)添加任务two
        Future futureTwo = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("start runable two");
            }
        });

        //(4)添加任务three
        Future futureThree = null;
        try {
            futureThree = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("start runable three");
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getLocalizedMessage());
        }

        try {
            System.out.println("task one finish " + futureOne.get());//(5)等待任务one执行完毕
            System.out.println("task two finish " + futureTwo.get());//(6)等待任务two执行完毕
            System.out.println("task three finish " + (futureThree == null ? null : futureThree.get()));// (7)等待任务three执行完毕
        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();//(8)关闭线程池,阻塞直到所有任务执行完毕
    }
   
   

  Using this strategy, because of the method of the report on the mission will cancel CancellationException throw an exception, so when using a try-catch) in get (catch exceptions. After running the program can exit normally found.

Guess you like

Origin www.cnblogs.com/jpfss/p/11671134.html