目录
好几天没写,最近有点烦躁,不知道从何开始,也不知道从哪里结束,真烦。虽然贼烦还是得继续。加油。
今天继续多线程系列,Java开发常用的不可避免的多线程问题,多线程问题一般就是锁,线程,线程池。
今天大概聊聊Java的线程池,我们游戏里有不同的线程池使用场景,有邮件的线程池,有入库的线程池,也有一些定时器的线程池,等等。
一、线程池是什么
线程池就是一个对象持有一堆线程,举个例子就是饿了么养的骑手团队。线程池就是这个团队,每个骑手都是一个线程。
二、为什么要用线程池?
假如现在商家有外卖单子,需要骑手去送单,这个时候的外卖任务就会派单给骑手,为什么要用线程池呐?
有几个好处,第一就是骑手的招聘是有成本的,等你有了外卖订单再去招聘,来不及了,不如平常养一些骑手,线程的创建和销毁的开销是巨大的。
第二就是不能一个单子来了就来一个骑手,这样的话骑手的数量很难控制,对于派单来说也存在很大的压力,会造成整个骑手团队的崩溃,对应的就是可以通过线程池控制系统内的线程数量,有效的避免大量的线程池争夺CPU资源而造成堵塞。
第三如果养了一个骑手团队,这样在骑手的管理上可以规范,以便提供更好的外卖服务,比如这种外卖超时,骑手打星等。对比线程池就是线程池可以提供定时、定期、单线程、并发数控制等功能。
三、看下类图,从整体上理解下
四、线程池的创建
线程池主要使用的四种
-
固定数量的线程池(FixedThreadPool)
-
定时线程池(ScheduledThreadPool )
-
可缓存线程池(CachedThreadPool)
-
单线程化线程池(SingleThreadExecutor)
五、线程池核心参数说明
首先看下如何构造一个线程池
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
核心参数说明:
六、几个疑问点
6.1、是怎么保证线程不销毁的?
核心线程会阻塞等待workQueue
6.2 提交任务有哪几种方式?
6.3 拒绝策略都有哪些?
拒绝策略(handler)当线程池的线程数达到最大线程数时,需要执行拒绝策略。拒绝策略需要实现RejectedExecutionHandler接口,并实现rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法。不过Executors框架已经为我们实现了4种拒绝策略:
AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。
6.4 线程池的关闭
关闭线程池可以调用shutdownNow和shutdown两个方法来实现
shutdownNow:对正在执行的任务全部发出interrupt(),停止执行,对还未开始执行的任务全部取消,并且返回还没开始的任务列表。
shutdown:当我们调用shutdown后,线程池将不再接受新的任务,但也不会去强制终止已经提交或者正在执行中的任务。
6.5 初始化线程池时线程数的选择
如果任务是IO密集型,一般线程数需要设置2倍CPU数以上,以此来尽量利用CPU资源。
如果任务是CPU密集型,一般线程数量只需要设置CPU数加1即可,更多的线程数也只能增加上下文切换,不能增加CPU利用率。
具体问题具体分析。
七、总结
线程池是项目中常用的,需要理解线程池的应用场景和构造函数,正确的使用线程池。
打字不容易,点赞,转发,关注三连,谢谢大家,对了,关注我公众号:【香菜聊游戏】有更多福利哦。
常规福利双手送上。
推荐阅读 点击标题可跳转