线程池简介
一、什么是线程池
线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗。
二、线程池的作用
线程创建是需要时间的,如果每次使用新线程的时候,都去创建线程,是比较耗时的。但是如果将线程先创建好,放到池子里面,用的时候直接从池子里面去取,就省略了创建线程的时间。这是一种使用空间来换取时间的策略。
另外,通过线程池,可以规定线程的名字,我可以知道我这个线程池当中有哪些线程执行了哪些任务,通过日志可以快速定位问题,便于管理。
三、线程池中的重要参数
-
核心线程数
当线程池的线程都忙碌时,再进来新任务时,由最小线程数扩容到核心线程数 -
最小线程数
项目启动的时候,初始化的线程数 -
最大线程数
当核心线程数满了,当队列也满了,再来新任务,就会创建新线程来执行这个新任务,直到线程数达到最大线程数。 -
队列大小
当线程数达到核心线程数,再进来的任务就会进入到队列,采用阻塞队列实现。 -
拒绝策略
AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程处理该任务。(最稳妥)
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。 -
存活时间
当线程超过多长时间不执行任务,处于空闲状态,线程池会将它回收,直到数量达到核心线程数。
四、线程池的工作原理
- 判断核心线程池是否已满,即已创建线程数是否小于核心线程数?没满则创建一个新的工作线程来执行任务。已满则进入下个流程。
- 判断工作队列是否已满?没满则将新提交的任务添加在工作队列,等待执行。已满则进入下个流程。
- 判断整个线程池是否已满,即已创建线程数是否小于最大线程数?没满则创建一个新的工作线程来执行任务,已满则交给拒绝策略来处理这个任务。
五、java中常见的线程池
newCachedThreadPool:
创建一个可缓存的无界线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收,则新建线程。当线程池中的线程空闲时间超过60s,则会自动回收该线程,当任务超过线程池的线程数则创建新的线程,线程池的大小上限为Integer.MAX_VALUE,可看作无限大。
newFixedThreadPool:
创建一个指定大小的线程池,可控制线程的最大并发数,超出的线程会在LinkedBlockingQueue阻塞队列中等待
newScheduledThreadPool:
创建一个定长的线程池,可以指定线程池核心线程数,支持定时及周期性任务的执行
newSingleThreadExecutor:
创建一个单线程化的线程池,它只有一个线程,用仅有的一个线程来执行任务,保证所有的任务按照指定顺序(FIFO,LIFO,优先级)执行,所有的任务都保存在队列LinkedBlockingQueue中,等待唯一的单线程来执行任务。
六、注意事项
- 核心线程数一般为cpu的核数
- 最大线程数一般设置为cpu的核数*2
- 最先派给线程池的任务不一定最先执行
- 阿里巴巴开发手册中强调在开发中只要使用多线程就需要用线程池去管理
- 阿里巴巴开发手册中强调不允许使用Executors创建线程池
参考
https://blog.csdn.net/qq_40093255/article/details/116990431
https://blog.csdn.net/u013541140/article/details/95225769
《阿里巴巴java开发手册》