Java中提供线程池
newCachedThreadPool
可缓存线程池,若线程池长度超过处理需要,则回收空线程,否则创建新线程,线程规模可无限大。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
newFixedThreadPool
定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
newScheduledThreadPool
定长线程池,支持定时及周期性任务执行,类似Timer。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
newSingleThreadExecutor
单线程 的线程池,支持FIFO, LIFO, 优先级策略。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
通过观察源码,其中四种线程的创建都是创建一个ThreadPoolExecutor。其中ThreadPoolExecutor是ExecutorService接口的实现类。
ExecutorService
定义
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
参数说明
corePoolSize:线程池中的线程保持数量,当设置超时时间设置后,在达到超时时间后不会保留
maximumPoolSize:线程池中允许最大线程数数量
keepAliveTime:核心线程数量保留时间
unit:保留时间的时间单位
workQueue:线程池中等待任务,如果当前对线程的需求超过了corePoolSize大小,才会放在这里;
threadFactory:创建线程工厂,线程池中创建线程使用的方法
handler:线程池满了,处理新的任务方式
BlockingQueue的实现
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
ArrayBlockingQueue
ArrayBlockingQueue是一个有边界的阻塞队列,它的内部实现是一个数组。有边界的意思是它的容量是有限的,我们必须在其初始化的时候指定它的容量大小,容量大小一旦指定就不可改变。
DelayQueue
DelayQueue阻塞的是其内部元素,DelayQueue中的元素必须实现 java.util.concurrent.Delayed接口,该接口只有一个方法就是long getDelay(TimeUnit unit),返回值就是队列元素被释放前的保持时间,如果返回0或者一个负值,就意味着该元素已经到期需要被释放,此时DelayedQueue会通过其take()方法释放此对象,DelayQueue可应用于定时关闭连接、缓存对象,超时处理等各种场景;
LinkedBlockingQueue
LinkedBlockingQueue阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。
PriorityBlockingQueue
PriorityBlockingQueue是一个没有边界的队列,它的排序规则和 java.util.PriorityQueue一样。需要注意,PriorityBlockingQueue中允许插入null对象。所有插入PriorityBlockingQueue的对象必须实现 java.lang.Comparable接口,队列优先级的排序规则就是按照我们对这个接口的实现来定义的。
SynchronousQueue
SynchronousQueue队列内部仅允许容纳一个元素。当一个线程插入一个元素后会被阻塞,除非这个元素被另一个线程消费。
RejectedExecutionHandler的实现
- AbortPolicy
- DiscardPolicy
- DiscardOldestPolicy
- CallerRunsPolicy
- 自定义
AbortPolicy
该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
DiscardPolicy
这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常
DiscardOldestPolicy
这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
因为队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除对头元素后再尝试入队。
CallerRunsPolicy
使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。就像是个急脾气的人,我等不到别人来做这件事就干脆自己干。
自定义
如果以上策略都不符合业务场景,那么可以自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口,并且实现rejectedExecution方法就可以了。具体的逻辑就在rejectedExecution方法里去定义就OK了。