【知识点】Java线程池

1. 池化技术

池化技术里听得最多的就是Java线程池、以及数据库连接池了。对于池化技术而言,其精髓就在于复用,复用池子里已经分配好的线程。

优点:线程是稀缺珍贵资源,减少对线程的创建、销毁工作,可以复用线程资源。
缺点:适合耗时较短的逻辑,若逻辑耗时,使用过多线程池可能导致系统宕机。

2. 运行过程

运行过程:
可以认为Java线程池是基于生产者-消费者模式(线程池的调用方为生产者,线程池里的线程为消费者)
1. 线程池刚创建时,里面没有一个线程(任务队列是作为参数传进来的)
2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
   a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
   b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
   c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
   d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会执行拒绝策略。
3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。(当然线程池也可以对核心线程进行回收,此时要设置核心线程的空闲时间)

3. 线程创建

对于java线程池来说,juc包Executors中已经提供了几种类型创建:

//1. 固定线程大小的线程池(无界队列)
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
//2. 单个线程线程池(无界队列)
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
//3. 无上限线程线程池(最大线程数没有限制)
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}
//4. 基于任务调度的线程池(最大线程数没有限制)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}

生产使用中,不建议使用上述方式创建。上述4种方式,对于队列大小或者线程个数的创建没有限制,当线程业务处理较为耗时时,会急剧消耗资源。

一般使用ThreadPoolExecutor的构造方法进行创建:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
  this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
}

4. 参数解析

主要参数如下:
1. corePoolSize:核心线程数
2. maximumPoolSize:最大线程数
3. keepAliveTime:当前线程池数量大于核心线程数时,多余的空闲线程的存活时间
4. unit:keepAliveTime 的单位
5. workQueue:任务队列
6. threadFactory:线程工厂,用于创建线程,一般用默认的即可
7. handler:拒绝策略

其中对于拒绝策略又有4种:
1. AbortPolicy : 直接抛弃,并抛出异常,阻止系统正常运行(默认)
2. CallerRunsPolicy : 有提交任务的主线程进行任务的处理
3. DiscardOldestPolicy : 抛弃最早的任务,并尝试将最新的任务加入线程池
4. DiscardPolicy : 直接抛弃,不抛出异常
5. 自定义拒绝策略

5. 线程关闭

shutdown():优雅关闭。不允许再提交新的任务,且等所有已提交的任务都执行完成后,才会真正关闭线程池
shutdownNow():强制关闭。返回还没执行的task列表,尝试停止正在执行的任务。

6. 源码解析

参考简书:彻底理解Java线程池原理(文章讲的很详细,写的也非常到位)

7. 业务场景

线程池适合于执行时间段的并发任务场景:
1. 执行时间短,业务逻辑较长时,可能存在多个线程次的占用,急剧消耗资源
2. 线程池的作用就是开启线程,并发执行,提高系统的吞吐量

【说明】有些地方未做验证,请保持怀疑态度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值