线程池的概念
线程池(ThreadPoolExecutor) 顾名思义,在一个“池”中存放多个线程。
与常量池、数据库连接池等思想是一样的,为的都是提高效率。
我们已经领教了多线程的优势,使用线程池也是为了能够扩大线程所具备的优势。通过并发编程、轻量级、频繁创建销毁的优势。
线程池的优势
在线程中进行创建和销毁需要同时调用用户态和内核态才能完成工作。而线程池的创建销毁只需要用户态即可完成操作,不需要与内核态进行交互。这在一定程度上提高了效率。
线程池属性介绍
在线程池的构造方法中,我们可以看到有以下几个参数:corePoolSize
maximumPoolSIze
keppAliveTime
TimeUnit
BlockingQueue
ThreadFactory
RejectExecutionHandler
- corePoolSize:核心线程数。在一个线程池刚被创建出来之后,首先创建的线程数量为核心线程数。如果核心线程足以完成任务,那么就不再添加多余的线程。如果任务过多,核心线程处理不过来,那么线程池就会自动创建出新的线程来一同解决这些任务。当任务解决完成之后,非核心线程就会被回收掉。
- maximumPoolSize:最大线程数。在核心线程数中我们知道,问题处理不过来以后机会创建出新的线程一同解决问题,但是线程总数量不能大于最大线程数。
- keepAliveTime:允许存活时间。在这里指的是非核心线程允许空闲的最大时间,当线程池空闲超过这一段时间之后,非核心线程就会被回收掉。
- TimeUnit:时间单位,与keepAliveTime相配合,假设keepAliveTime = 1,TImeUnit = Day,即非核心线程存活时间1天。
- BlockingQueue:任务队列。在线程池中使用阻塞队列存储需要完成的任务。线程池会提供submit方法,让其他线程把任务交给线程池。
- ThreadFactory:线程工厂。用来创建线程的工厂类。
- RejectExecutionHandler:拒绝策略。在拒绝策略中一共分为四种方式
(1)AbortPolicy:线程池直接抛出异常。
(2)CallerRunsPolicy:线程池任务已满,让添加任务的线程本身执行这一任务。
(3)DiscardOladestPolicy:线程丢弃掉最老的任务,让新的任务在队列中排队。
(4)DiscardPolicy:丢弃掉新添加进来的任务,不予理会。
线程池的使用
标准库中线程池使用方法过于繁琐,于是有了线程池的工厂类Executors,通过该工厂类能够提升代码的效率,也更便捷的使用。
//1.根据任务数量自动扩容
ExecutorService service = Executors.newCachedThreadPool();
//2.固定线程数量
Executors.newFixedThreadPool(3);
//3.创建只包含单线程的线程池
Executors.newSingleThreadExecutor();
//4.创建一个固定线程个数,但是任务超时执行的线程池
Executors.newScheduledThreadPool(4);
为线程池添加任务的submit方法也包含在其中
service.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello submit");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
在线程池工作完成之后,线程是不会被回收掉的。仍然处于等待状态。
简单实现线程池
简单实现一个线程池所需要的基本属性有:阻塞队列存放任务,线程数量暂时固定,submit方法,下面代码简单作为参考。
所创建的线程thread通过while循环不断获取queue中的任务,如果没有任务就阻塞等待。submit为阻塞队列添加任务。
class MyThreadPool {
private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
public MyThreadPool(int n) {
for (int i = 0; i < n; i++) {
Thread thread = new Thread(()-> {
while (true) {
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
}
}
public void submit(Runnable runnable) throws InterruptedException {
queue.put(runnable);
}
}
总结
线程池是一种很实用的类,可以极大的提高效率,同时也具有很强的灵活性,值得学习。
线程池源码☞线程池