简述ThreadPoolExecutor的工作原理

ThreadPoolExecutor的内部工作原理,整体思路总结为5句话:

  1. 如果线程池大小poolSize小于corePoolSize,则创建新线程执行任务。
  2. 如果线程池大小poolSize大于corePoolSize,且等待队列未满,则进入等待队列。
  3. 如果线程池大小poolSize大于corePoolSize且小于maximumPoolSize,且等待队列已满,则创建新线程执行任务。
  4. 如果线程池大小poolSize大于corePoolSize且大于maximumPoolSize,且等待队列已满,则调用拒绝策略来处理该任务。
  5. 线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在keepAliveTime里等不到新的任务了,那么线程就会退出。

ThreadPoolExecutor线程池中拒绝策略:

  1. AbortPolicy:为java线程池默认的阻塞策略,不执行此任务,而且会直接抛出一个执行时异常,切记TreadPoolExecutor.execute需要try catch,否则程序会直接退出。
  2. DiscardPolicy:直接抛弃,任务不执行,空方法
  3. DiscardOldestPolicy:从队列里面抛弃head的一个任务,并再次execute 此任务(task)
  4. CallerRunsPolicy:在调用execute的线程里面执行此command,会阻塞入口。
  5. 用户自定义拒绝策略:实现RejectdExecutionHandler,并自己定义策略模式。

举例说明:

使用直接丢弃任务本身的拒绝策略:DiscardPolicy

import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;

    public class ExecutorDemo {

        private static  SimpleDateFormat sdf  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        public static void main(String[] args) {
            int corePoolSize = 1;
            int maximumPoolSize = 1;
            BlockingQueue queue = new  ArrayBlockingQueue(1);
            ThreadPoolExecutor pool = new ThreadPoolExecutor(corePoolSize,  maximumPoolSize, 
                    0, TimeUnit.SECONDS, queue ) ;
            pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy ());
            for(int i=0;i<10;i++){
                final int index = i;
                pool.submit(new Runnable(){

                    @Override
                    public void run() {
                        log(Thread.currentThread().getName()+"begin run task :"+index);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        log(Thread.currentThread().getName()+" finish run  task :"+index);
                    }

                });
            }

            log("main thread before sleep!!!");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log("before shutdown()");

            pool.shutdown();

            log("after shutdown(),pool.isTerminated=" + pool.isTerminated());
            try {
                pool.awaitTermination(1000L, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log("now,pool.isTerminated=" + pool.isTerminated());
        }

        protected static void log(String string) {
            System.out.println(sdf.format(new Date())+"  "+string);
        }

    }

运行结果:

    2016-08-04 22:29:21  main thread before sleep!!!
    2016-08-04 22:29:21  pool-1-thread-1begin run task :0
    2016-08-04 22:29:22  pool-1-thread-1 finish run  task :0
    2016-08-04 22:29:22  pool-1-thread-1begin run task :1
    2016-08-04 22:29:23  pool-1-thread-1 finish run  task :1
    2016-08-04 22:29:25  before shutdown()
    2016-08-04 22:29:25  after shutdown(),pool.isTerminated=false
    2016-08-04 22:29:25  now,pool.isTerminated=true

从结果可以看出,只有task0和task1两个任务被执行了。

为什么只有task0和task1两个任务被执行了呢?

过程是这样的:由于我们的任务队列的容量为1.当task0正在执行的时候,task1被提交到了队列中但是还没有执行,受队列容量的限制,submit提交的task2~task9就都被直接抛弃了。因此就只有task0和task1被执行了。

使用丢弃任务队列中比较久的任务的拒绝策略:DiscardOldestPolicy

如果将拒绝策略改为:DiscardOldestPolicy(丢弃队列中比较久的任务)

运行结果为:

    2016-08-04 22:31:58  pool-1-thread-1begin run task :0
    2016-08-04 22:31:58  main thread before sleep!!!
    2016-08-04 22:31:59  pool-1-thread-1 finish run  task :0
    2016-08-04 22:31:59  pool-1-thread-1begin run task :9
    2016-08-04 22:32:00  pool-1-thread-1 finish run  task :9
    2016-08-04 22:32:02  before shutdown()
    2016-08-04 22:32:02  after shutdown(),pool.isTerminated=false
    2016-08-04 22:32:02  now,pool.isTerminated=true

从结果可以看出,只有task0和task9被执行了。

使用将任务将由调用者线程去执行的拒绝策略:CallerRunsPolicy

如果将拒绝策略改为:CallerRunsPolicy(即不用线程池中的线程执行,而是交给调用方来执行)

运行结果为:

    2016-08-04 22:33:07  mainbegin run task :2
    2016-08-04 22:33:07  pool-1-thread-1begin run task :0
    2016-08-04 22:33:08  main finish run  task :2
    2016-08-04 22:33:08  mainbegin run task :3
    2016-08-04 22:33:08  pool-1-thread-1 finish run  task :0
    2016-08-04 22:33:08  pool-1-thread-1begin run task :1
    2016-08-04 22:33:09  pool-1-thread-1 finish run  task :1
    2016-08-04 22:33:09  main finish run  task :3
    2016-08-04 22:33:09  mainbegin run task :5
    2016-08-04 22:33:09  pool-1-thread-1begin run task :4
    2016-08-04 22:33:10  main finish run  task :5
    2016-08-04 22:33:10  mainbegin run task :7
    2016-08-04 22:33:10  pool-1-thread-1 finish run  task :4
    2016-08-04 22:33:10  pool-1-thread-1begin run task :6
    2016-08-04 22:33:11  main finish run  task :7
    2016-08-04 22:33:11  mainbegin run task :9
    2016-08-04 22:33:11  pool-1-thread-1 finish run  task :6
    2016-08-04 22:33:11  pool-1-thread-1begin run task :8
    2016-08-04 22:33:12  main finish run  task :9
    2016-08-04 22:33:12  main thread before sleep!!!
    2016-08-04 22:33:12  pool-1-thread-1 finish run  task :8
    2016-08-04 22:33:16  before shutdown()
    2016-08-04 22:33:16  after shutdown(),pool.isTerminated=false
    2016-08-04 22:33:16  now,pool.isTerminated=true

从结果可以看出,没有任务被抛弃,而是将由的任务分配到main线程中执行了。


你可能感兴趣的:(java线程池)