线程池(重点):3大方法,7大参数,4种拒绝策略
程序运行的本质:占用系统资源!优化资源的使用!----->池化技术
池化技术的好处: 1.降低资源的消耗 2.提高响应速度 3.方便管理
线程复用,可以控制最大并发数,管理线程。
在 JDK5 版本中增加了内置线程池实现 ThreadPoolExecutor,同时提供了Executors 来创建不同类型的线程池。Executors 中提供了以下常见的线程池创 建方法:
newSingleThreadExecutor:一个单线程的线程池。如果因异常结束,会再创 建一个新的,保证按照提交顺序执行。
newFixedThreadPool:创建固定大小的线程池。根据提交的任务逐个增加线程, 直到最大值保持不变。如果因异常结束,会新创建一个线程补充。
newCachedThreadPool:创建一个可缓存的线程池。会根据任务自动新增或回 收线程。
ThreadPoolExecutor 类
Java.uitl.concurrent.ThreadPoolExecutor 类是线程池中最核心的一个类。
ThreadPoolExecutor 继承了 AbstractExecutorService 类,并提供了四个构造
器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调
用的第四个构造器进行的初始化工作。
构造器中各个参数的含义
七大核心参数:1.核心线程池大小 2.最大核心线程池大小 3.超时多久没人使用就会释放
4.超时单位 5.阻塞队列 6.线程工厂,创建线程的,一般不动 7.拒绝策略
corePoolSize :核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,在创建了线程池后,线程池中的线程数为 0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线 程数目达到 corePoolSize 后,就会把到达的任务放到缓存队列当中;除非调用了 prestartAllCoreThreads()或者 prestartCoreThread()方法,从这 2 个方法的名 字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建 corePoolSize 个线程或者一个线程。
maximumPoolSize :线程池最大线程数,这个参数也是一个非常重要的参数, 它表示在线程池中最多能创建多少个线程;
keepAliveTime :表示线程没有任务执行时最多保持多久时间会终止。默认情 况下,只有当线程池中的线程数大于 corePoolSize 时,keepAliveTime 才会起 作用,直到线程池中的线程数不大于 corePoolSize,即当线程池中的线程数大 于corePoolSize 时,如果一个线程空闲的时间达到 keepAliveTime,则会终止, 直到线程池中的线程数不超过 corePoolSize。
unit :参数 keepAliveTime 的时间单位,有 7 种取值,在 TimeUnit 类中有 7
种静态属性:
workQueue :一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很 重要,会对线程池的运行过程产生重大影响。
threadFactory :线程工厂,主要用来创建线程。
handler :表示当拒绝处理任务时的策略。
提交任务到线程池的执行过程:一般只开核心线程,当阻塞队列满了以后,将会启动最大核心线程池大小。当处于最大核心线程下时,依然有线程要加入阻塞队列,启动拒绝策略。
线程池中的队列
线程池有以下工作队列:
ArrayBlockingQueue: 是一个用数组实现的有界阻塞队列,创建时必须设置长度,,按 FIFO 排序量。
LinkedBlockingQueue: 基于链表结构的阻塞队列,按 FIFO 排序任务,容量可以选择进行设置,不设置是一个最大长度为 Integer.MAX_VALUE。
线程池的拒绝策略
构造方法的中最后的参数 RejectedExecutionHandler 用于指定线程池的拒绝策略。当请求任务不断的过来,而系统此时又处理不过来的时候,我们就需要采 取对应的策略是拒绝服务。
默认有四种类型:
AbortPolicy 策略:该策略会直接抛出异常,阻止系统正常工作。
CallerRunsPolicy 策略:只要线程池未关闭,该策略在调用者线程中运行当前的 任务(如果任务被拒绝了,则由 提交任务的线程(例如:main) 直接执行此任务)。
DiscardOleddestPolicy 策略:该策略将丢弃最老的一个请求,也就是即将被执 行的任务,并尝试再次提交当前任务。
DiscardPolicy 策略:该策略丢弃无法处理的任务,不予任何处理。
execute 与 submit 的区别
执行任务除了可以使用 execute 方法还可以使用 submit 方法。它们的主要区别是:execute 适用于不需要关注返回值的场景,submit 方法适用于需要关注返 回值的场景。
关闭线程池
关闭线程池可以调用 shutdownNow 和 shutdown 两个方法来实现。
shutdownNow:对正在执行的任务全部发出 interrupt(),停止执行,对还未开始执行的任务全部取消,并且返回还没开始的任务列表。
shutdown:当我们调用 shutdown 后,线程池将不再接受新的任务,但也不会 去强制终止已经提交或者正在执行中的任务。
最大线程到底如何定义(调优)最大值
1.CPU密集型,几核就是几,可以保持CPU的效率最高!
2.IO密集型,判断程序中十分耗费IO的线程个数,一般设置为其的两倍。
获得当前计算机的CPU核数
Runtime.getRuntime().availableProcessors(); //获得CPU核数