线程池的工作原理

ThreadPoolExecutor(int corePoolSize,// 外围线程数                   int maximumPoolSize,//最大线程数                   long keepAliveTime,//闲暇线程存活工夫                   TimeUnit unit,//存活工夫单位                   BlockingQueue<Runnable> workQueue,//阻塞队列                   RejectedExecutionHandler handler)//回绝策略

当ThreadPoolExecutor线程池被创立的时候,里边是没有工作线程的,直到有工作进来(执行了execute办法)才开始创立线程去工作,工作原理如下(即execute办法运行原理):

调用线程池的execute办法的时候如果以后的工作线程数 小于 外围线程数,则创立新的线程执行工作;否则将工作退出阻塞队列。如果队列满了则依据最大线程数去创立额定(外围线程数以外)的工作线程去执行工作;如果工作线程数达到了最大线程数,则依据回绝策略去执行。存活工夫到期的话只是回收外围线程(maximumPoolSize - corePoolSize)以外的线程
// 分3个步骤进行:// 1. 如果运行的线程少于corePoolSize,请尝试应用给定的命令作为第一个线程启动一个新线程的工作。对addWorker的调用会主动查看runState和workerCount,这样能够避免虚伪警报的减少当它不应该的时候,返回false。// 2. 如果工作能够胜利排队,那么咱们依然须要来再次查看咱们是否应该增加线程(因为自从上次查看后,现有的曾经死了)或者那样自进入此办法后池就敞开了。所以咱们从新查看状态,并在必要时回滚队列进行,或启动一个新线程(如果没有线程)。// 3.如果咱们不能将工作放入队列,那么咱们尝试增加一个新的线程。如果它失败了,咱们晓得咱们被敞开或饱和了所以回绝这个工作。public void execute(Runnable command) {        if (command == null)            throw new NullPointerException();        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);    }

五种线程池

ExecutorService threadPool = null;threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 管制threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池threadPool = Executors.newScheduledThreadPool(2);threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比拟多  

ThreadPoolExecutor参数:

public class ThreadPoolExecutor extends AbstractExecutorService {    .....    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);    ...}

参数含意以及性能:

  • corePoolSize:外围池的大小,这个参数跟前面讲述的线程池的实现原理有十分大的关系。在创立了线程池后,默认状况下,线程池中并没有任何线程,而是期待有工作到来才创立线程去执行工作,除非调用了prestartAllCoreThreads()或者prestartCoreThread()办法,从这2个办法的名字就能够看出,是预创立线程的意思,即在没有工作到来之前就创立corePoolSize个线程或者一个线程。默认状况下,在创立了线程池后,线程池中的线程数为0,当有工作来之后,就会创立一个线程去执行工作,当线程池中的线程数目达到corePoolSize后,就会把达到的工作放到缓存队列当中;
  • maximumPoolSize:线程池最大线程数,这个参数也是一个十分重要的参数,它示意在线程池中最多能创立多少个线程;
  • keepAliveTime:示意线程没有工作执行时最多放弃多久工夫会终止。默认状况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程闲暇的工夫达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。然而如果调用了allowCoreThreadTimeOut(boolean)办法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
  • unit:参数keepAliveTime的工夫单位,有7种取值,在TimeUnit类中有7种动态属性:
TimeUnit.DAYS;               //天TimeUnit.HOURS;             //小时TimeUnit.MINUTES;           //分钟TimeUnit.SECONDS;           //秒TimeUnit.MILLISECONDS;      //毫秒TimeUnit.MICROSECONDS;      //奥妙TimeUnit.NANOSECONDS;       //纳秒

workQueue:一个阻塞队列,用来存储期待执行的工作,这个参数的抉择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种抉择:

ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue;

ArrayBlockingQueue和PriorityBlockingQueue应用较少,个别应用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue无关。

  • threadFactory:线程工厂,次要用来创立线程;
  • handler:示意当回绝解决工作时的策略,有以下四种取值:
    • ThreadPoolExecutor.AbortPolicy:(默认)抛弃工作并抛出RejectedExecutionException异样。
    • ThreadPoolExecutor.DiscardPolicy:也是抛弃工作,然而不抛出异样。
    • ThreadPoolExecutor.DiscardOldestPolicy:抛弃队列最后面的工作,而后从新尝试执行工作(反复此过程)
    • ThreadPoolExecutor.CallerRunsPolicy:由调用线程解决该工作

四种回绝策略

RejectedExecutionHandler rejected = null;rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢工作抛出异样rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢工作不抛异样rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的工作删,之后再尝试退出队列rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果增加到线程池失败,那么主线程会本人去执行该工作;如果执行程序已敞开(主线程运行完结),则会抛弃该工作

当然也能够依据利用场景实现 RejectedExecutionHandler 接口,自定义饱和策略,如记录 日志或长久化存储不能解决的工作

三种阻塞队列

BlockingQueue<Runnable> workQueue = null;workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界workQueue = new SynchronousQueue<>();//无缓冲的期待队列,无界

起源:blog.csdn.net/AIGUO666666/article/details/103251145

近期热文举荐:

1.1,000+ 道 Java面试题及答案整顿(2021最新版)

2.别在再满屏的 if/ else 了,试试策略模式,真香!!

3.卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!