线程池的工作原理
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开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!