文章目录
- 1. 什么是线程池?
- 2. 线程池的应用
- 3. 自己实现线程池
1. 什么是线程池?
线程池就相当于一个池子,里面有很多的创建好的线程,可以进行统一的管理。当我们使用线程的时候,直接从里面调取,而不用在频繁的创建与销毁。
线程池的优点:
- 降低了线程创建销毁的开销:不用频繁的创建销毁线程,减少了资源 的开销;
- 提高系统的稳定性:线程池中的线程是有限的的,避免了创建了大量线
程,造成系统崩溃;- 提高资源的利用率:线程池能够合理的分配系统资源(CPU时间,内存等),提高资源的利用率;
- 方便管理线程:线程池中的线程可以统一进行管理,方便创建,暂停,启动,销毁等操作;
- 提高响应速度:当有任务来后,不需要在创建线程,只需要分配一个线程,速度更快;
2. 线程池的应用
Java标准库中含有线程池,我们可以直接使用。
例如:
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(() -> {
System.out.println(Thread.currentThread().getName() + " hello");
});
}
- Executors.newFixedThreadPool(4)可以创建一个含有四个线程的线程池,返回值类型为ExecutorService;
- submit是ExecutorService类中的一个重要方法,可以将一个任务放到线程池中。
当然并不止这一种线程池的创建,还有:
newFixedThreadPool: 创建固定线程数的线程池
newCachedThreadPool: 创建线程数目动态增长的线程池.
newSingleThreadExecutor: 创建只包含单个线程的线程池.
newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.
上面有一个细节,线程池的创建并不是直接new一个,而是通过Executors调用。Executors本质是ThreadPoolExecutor类的封装,是一个工厂模式,调用起来不用传各种参,更加简单。
如果我们直接new:
会发现非常的麻烦,但是我们可以很直观的知道线程池的结构使用。
3. 自己实现线程池
同前面定时器一样,要自己实现一个线程池,实现前我们要知道线程池的构造:
- 核心操作为 submit, 将任务加入线程池中
- 使用 Worker 类描述一个工作线程. 使用 Runnable 描述一个任务.
- 使用一个 BlockingQueue 组织所有的任务 每个 worker 线程要做的事情:
- 不停的从 BlockingQueue 中取任务并执行. 指定一下线程池中的最大线程数
- maxWorkerCount; 当当前线程数超过这个最大值时, 就不再新增 线程了.
代码:
class MyThreadPool{
//堵塞循环队列,存放要执行的任务
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
//模拟线程池的submit方法
public void submit(Runnable runnable) throws InterruptedException {
//每次调用此方法,在队列放入一个任务
queue.put(runnable);
}
//线程池,n为线程个数
public MyThreadPool(int n){
for (int i = 0; i < n; i++) {
Thread t = new Thread(() -> {
//n个线程不停的循环,执行任务下
while(true){
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
}
public class Test2 {
public static void main(String[] args) throws InterruptedException {
MyThreadPool myThreadPool = new MyThreadPool(4);
for (int i = 0; i < 10; i++) {
myThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " hello!");
}
});
}
}
}
运行结果: