一、什么是线程池
二、使用线程池的好处
三、涉及到的类和接口
常用的线程池接口和类都在 java.util.concurrent包下,大致为:
ExecutorService接口的实现类最常用的为以下两个:
和 Array -> Arrays、Collection -> Collections 一样,线程池的创建也是有工具类可以使用的:
四、线程池种类
在 JDK 8 以后,一共有 5 种线程池,分别为:
这些线程池都能由 Executors 工具类来进行创建,分别对应以下方法:
对于 newWorkStealingPool 的补充:
五、如何使用线程池
(一)使用步骤
(二)案例代码
需求:使用线程池管理线程来简单的模拟买票程序。
public class Demo(){
public static void main(String[] args) {
test();
}
public static void test(){
//1、创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(4);
//2、创建任务
Runnable runnable = new Runnable(){
private int tickets = 100;
@Override
public void run() {
while (true){
if(tickets <= 0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+tickets+"张票");
tickets--;
}
}
};
//3、将任务提交到线程池(需要几个线程来执行就提交几次)
for (int i=0; i<5; i++){
pool.submit(runnable);
}
//4、关闭线程池
pool.shutdown();
}
补充:
execute() 和 submit() 的区别:
六、线程池底层源码查看
newFixedThreadPool
newCachedThreadPool
newSingleThreadExecutor
newScheduledThreadPool
七、线程池7大参数
ThreadPoolExecutor 的底层源码:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
八、线程池底层工作原理
九、线程池的4大拒绝策略
线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。
JDK 内置的拒绝策略如下:
以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler 接口。
十、线程池的实际使用
通过查看 Executors 提供的默认线程池的底层源码后,我们会发现其有如下弊端:
1)FixedThreadPool 和 SingleThreadPool:
2)CachedThreadPool 和 ScheduledThreadPool:
并且在《阿里巴巴Java开发手册》中也有指出,线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式手动创建,这样的处理方式能让程序员更加明确线程池的允许规则,从而规避资源耗尽的风险。
小结:在实际开发中不会使用 Executors 创建,而是手动创建,自己指定参数。
十一、线程池的手动创建
以上的参数是随手写的,实际开发中参数的设置要根据业务场景以及服务器配置来进行设置。
十二、线程池配置合理线程数
设置线程池的参数时,需要从以下 2 个方面进行考虑:
(一)CPU 密集型
(二)IO 密集型
线程数的设置参考文章:
Java新手,若有错误,欢迎指正!