目录
一、线程池是什么
线程池主要功能就是提升程序的执行效率的,为了减少冗余的创建,就是减少每次启动、销毁线程的损耗。
二、标准库中的线程池
2.1 标准库创建线程的几种方式
public class ThreadDemo17 {
public static void main(String[] args) {
//创建固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
//创建线程数目动态增长的线程池
ExecutorService pool1 = Executors.newCachedThreadPool();
//创建只包含单个线程的线程池
ExecutorService pool2 = Executors.newSingleThreadExecutor();
//设定延迟事件后执行命令,也就是设置一个带定时器功能的线程池
ExecutorService pool3 = Executors.newScheduledThreadPool(10);
}
}
2.2 创建线程池和创建对象的对比
创建线程池采用了工厂模式,用了ExecutorService的静态方法,因为不用这种方法的话,如果都传两个参数,编译器无法分辨线程池的特性,而采用工厂模式的话就可以随用随取。
2.3 ThreadPoolService
java中提供了线程池的相关标准ThreadPoolService
介绍下这个方法的相关参数:
corePoolSize:表示核心线程数
maximumPoolSize:最多线程数(可以存在临时线程,但是核心线程数和临时线程数之和有一个界限)
keepAliveTime:非核心线程数存活的最大等待时间
unit:keepAliveTime的时间单位
workQueue:线程池的任务队列
threadFactory:线程工厂 线程创建的方案
handler:拒绝策略 描述如果当前任务队列任务满了,以什么方式拒绝
2.4 线程拒绝策略(handler)
ThreadPoolExecutor.AbortPolicy
:
如果任务队列中的任务满了,如果再添加任务,直接抛出异常RejectedExecutionException
举一个例子:如果老师给你布置了很多任务,还想给你再添加一个任务,你受不了了,直接哭了出来。
ThreadPoolExecutor.CallerRunsPolicy:如果任务队列中的任务满了,再添加任务,谁添加的谁负责
举一个例子:
如果老师给你布置了很多任务,还想给你再添加一个任务,你说你再添加你自己去做,我不做。
ThreadPoolExecutor.DiscardOldestPolicy:如果任务队列中的任务满了,再添加任务,我就会丢弃最老的任务,把新的任务添加进来
举一个例子:
如果老师给你布置了很多任务,还想给你再添加一个任务,我会先把时间最早的任务丢弃,把最新的任务添加进来。
ThreadPoolExecutor.DiscardPolicy:如果任务队列中的任务满了,再添加任务,就丢弃要添加的任务
举一个例子:
如果老师给你布置了很多任务,还想给你再添加一个任务,你直接无视他新布置的任务。
三、手动实现一个线程池
1、使用一个Worker类描述一个工作线程,使用Runnable描述一个任务
2、线程池的核心操作为submit,将任务加入线程池中
3、使用一个阻塞队列(BlockingQueue)组织所有任务
4、每个worker线程要做的任务:不停的从BlockingQueue中去任务并执行
5、指定一下线程池的最大线程数,当当前线程数超过这个最大值时,就不再新增线程了
class Worker {
//使用阻塞队列来组织任务
BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>(100);
//添加任务
public void submit(Runnable runnable) throws InterruptedException {
queue.put(runnable);
}
//实现一个固定线程数的线程池
public Worker(int n) {
for (int i = 0; i < n; i++) {
Thread t = new Thread(() -> {
try {
while (true) {
Runnable runnable = queue.take();
runnable.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
}
}
}
public class ThreadDemo18 {
public static void main(String[] args) throws InterruptedException {
Worker worker = new Worker(10);
for (int i = 0; i < 1000; i++) {
int number = i;
worker.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello " + number);
}
});
}
}
}
运行结果: