线程池
池的概念意味着可以复用, 减少创建, 销毁线程的消耗
即事先把需要使用的线程创建好, 放到 “池” 中, 需要的时候从 “池” 里取, 用完再放回 池里取
这样全程只创建和销毁线程一次(之说是一次哦, 没说一次创建和销毁多少个)即可
标准库线程池的使用
public class Main{
public static void main(String[] args) {
// 使用工厂方法创建线程池 (工厂方法其实是为了"填构造方法的坑 ... 此处不细说了")
ExecutorService pool = Executors.newFixedThreadPool(10); //线程池的大小设置为 10 ,即该线程池中有10个线程
for (int i = 0; i < 1000; i++) {
int x = i; //这里不用i, 而是再写个x. 是因为变量捕获
pool.submit(new Runnable() { //每一次往线程池中提交一个任务, 都会使得池中空闲的一个线程来执行该任务, 任务执行完毕后, 该线程再回到线程池, 以待下次使用
@Override
public void run() {
System.out.println("hello " + x);
}
});
}
}
}
运行结果
可以看到, 打印的结果是无序的, 说明线程池中线程拿到任务后,依旧是抢占式执行, 随机调度
循环结束后,进程并未结束, 说明线程池中的线程, 都是 前台线程
Executors 创建线程池的几种方式
而 Executors 本质上是 ThreadPoolExecutor 类的封装
ThreadPoolExecutor
ThreadPoolExecutor 提供了更多的可选参数, 可进一步细化线程池行为的设定
Java 官方文档中可以查看 ThreadPoolExecutor 类的构造方法
我们来仔细研究一下构造方法的参数
corePoolSize: 核心线程数量
maximumPoolSize: 最大线程数量 (核心线程 + 临时线程)
keepAliveTime: 临时线程的最大存活时间(如果无任务运行的话)
unit: 时间的单位(时分秒 …)
workQueue: 线程池的任务队列
threadFactory: 创建线程的工厂, 参与具体的创建线程工作
handler: 拒绝策略
其中拒绝策略的参数有以下几个:
拒绝策略: 如果任务队列已满, 仍往阻塞队列里添加任务, 那么将采取先选定策略来应对
ThreadPoolExecutor.AbortPolicy: \ 就直接抛出异常
ThreadPoolExecutor.CallerRunsPolicy: 多出来的任务, 谁添加的, 谁负责执行
ThreadPoolExecutor.DiscardOldestPolicy: 丢弃最早的任务
ThreadPoolExecutor.DidcardPolicy: 丢弃最新添加的任务
手写线程池 (简单实现)
主要是依靠 BlockingQueue – 阻塞队列来实现的, 阻塞队列在我之前的博客里也手写过, 所以在此算是偷懒了
// 手写线程池
class MyThreadPool {
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 创建含有 n 个线程的线程池 (构造方法)
public MyThreadPool(int n) {
for (int i = 0; i < n; i++) {
Thread t = new Thread(() -> {
while(true) {
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
// 注册任务给线程池
public void submit(Runnable runnbale) {
try {
queue.put(runnbale);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main{
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(10);
for(int i=0;i<1000;i++) {
int n = i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello " + n);
}
});
}
}
}
运行结果