//工作中只用这种
//最大线程数定义 1.CPU密集型 几核就是几 可保证CPU效率最高
Runtime.getRuntime().availableProcessors();//获取CPU核数
//IO密集型 判断程序中十分消耗IO资源线程大于这个数
// ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,//核心线程数
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(2,//核心线程数
5,//最大线程数
1,//超时时间
TimeUnit.SECONDS,//单位秒
new LinkedBlockingQueue<>(3),//任务队列,设置队列大小
Executors.defaultThreadFactory(),//线程工厂,默认线程工厂
new ThreadPoolExecutor.AbortPolicy());//拒绝策略
定长线程池(FixedThreadPool)
//特点:只有核心线程,线程数量固定,执行完立即回收。
//任务队列为链表结构的有界队列:LinkedBlockingQueue
//一个基于链表结构的阻塞队列,此队列按FIFO (先进先出)排序元素,
//吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
//应用场景:一个固定大小的线程池,可以用于已知并发压力的情况下,对线程数做限制,控制线程最大并发数。
ExecutorService executorService = Executors.newFixedThreadPool(5);
try {
//最大承载为队列+最大线程数
for (int i = 0; i < 10; i++) {
//使用线程池创建线程
scheduledExecutorService.execute(() -> {
System.out.println(Thread.currentThread().getName());
});
}
}finally {
//线程池用完要关闭
scheduledExecutorService.shutdown();
}
单线程化线程池(SingleThreadExecutor)
//特点:只有 1 个核心线程,无非核心线程,执行完立即回收。
// 任务队列为链表结构的有界队列:LinkedBlockingQueue
// 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出)排序元素吞吐量通常要高于ArrayBlockingQueue。
// 静态工厂方法Executors.newFixedThreadPool()使用了这个队列
// 应用场景:一个单线程的线程池,可以用于需要保证顺序执行的场景,并且只有一个线程在执行。
// 不适合并发但可能引起 IO 阻塞性及影响 UI 线程响应的操作,如数据库操作、文件操作等。
ExecutorService executorService = Executors.newSingleThreadExecutor();
可缓存线程池(CachedThreadPool)
//特点:无核心线程,非核心线程数量无限,执行完闲置 60s 后回收。
//任务队列为不存储元素的阻塞队列:SynchronousQueue
//一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,
// 否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,
// 静态工厂方法Executors.newCachedThreadPool使用了这个队列。
// 应用场景:执行大量、耗时少的任务。一个可以无限扩大的线程池,比较适合处理执行时间比较小的任务。
ExecutorService executorService = Executors.newCachedThreadPool();
//定时线程池(ScheduledThreadPool )
//特点:核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收。
//任务队列为延时阻塞队列:DealyQueue
//应用场景:执行定时或周期性的任务。定时启动的线程池,适用于需要多个后台线程执行周期任务的场景。
ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(5);
线程池的核心参数:
corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。
threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。(一般不用动)
handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。
线程池的拒绝策略:
当请求任务不断的过来,而系统此时又处理不过来的时候,我们需要采取的策略是拒绝服务。RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。在ThreadPoolExecutor中已经包含四种处理策略。
AbortPolicy(中止策略)策略:该策略会直接抛出异常,阻止系统正常工作。
CallerRunsPolicy 策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。
DiscardOleddestPolicy策略: 该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。
DiscardPolicy策略:忽略新任务;不予任何处理。
除了JDK默认提供的四种拒绝策略,我们可以根据自己的业务需求去自定义拒绝策略,自定义的方式很简单,直接实现RejectedExecutionHandler接口即可。
execute和submit的区别:
线程池执行任务是用的execute方法,除了execute方法,还有一个submit方法也可以执行我们提交的任务。
这两个方法有什么区别呢?分别适用于在什么场景下呢?
execute适用于不需要关注返回值的场景,只需要将线程丢到线程池中去执行就可以了。
submit方法适用于需要关注返回值的场景