目录
什么是线程池?
线程池是多线程案例中非常重要的一个部分,线程池的使用可以很好的减少每次启动、销毁线程的损耗.
在之前的学习中,接触过字符串常量池以及数据库连接池,根据之前的认识,池的作用就是缓存。
线程池,即初始化(new线程池对象的时候)就创建了一定数量的线程,这些创建的线程不断地从阻塞队列中取任务,相当于是消费者。其他线程(生产者)只需要不断提交任务到线程池中。
举个例子来解释线程池
线程池就相当于是一个快递公司,公司开始创建时有2个正式员工(即new线程池对象池创建的线程数),阻塞队列就是快递公司的仓库,这两个正式员工不断地从仓库中取出快递去送,送完之后再回来取其他快递去送,相当于整个过程中一直这两个正式员工一直存在,不能辞退(即这两个线程不能销毁,核心线程),这样就有效的减少了每次启动、销毁线程的损耗。
线程池的优势:线程的创建和销毁都是有一定的代价(性能的损耗),使用线程池就可以重复使用线程来执行多组任务(类似于缓存,起到线程复用的目的).
如何创建线程池?
普通创建
Java api文档中的构造方法
· corePoolSize:核心线程数,即newThreadPollExecutor对象时初始化创建的线程数
· maximumPoolSIze:线程池最大线程数(核心线程以及临时线程)
· keepAliveTime:临时线程允许的空闲时间
· unit:keepAliveTime的时间单位
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
//创建一个线程池: 开了一个快递公司
ThreadPoolExecutor pool = new ThreadPoolExecutor(
5,
10,
60,
TimeUnit.SECONDS,
//一般不使用无边界的阻塞队列,因为内存有限
new ArrayBlockingQueue<>(10000),
//拒绝策略: 一般最多使用CallerRunsPolicy,或自己实现
new ThreadPoolExecutor.CallerRunsPolicy()
);
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
}
}
快捷创建
· newFixedThreadPool:创建固定线程数的线程池
· newSingleThreadExecutor:创建只包含单个线程的线程池
· newCachedThreadPool:创建线程数目动态增长的线程池
· newScheduledThreadPool:计划任务的线程池,相当于进阶版的定时器
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceDemo {
public static void main(String[] args) {
//固定大小的线程池
ExecutorService fixed = Executors.newFixedThreadPool(4);
//单线程池
ExecutorService single = Executors.newSingleThreadExecutor();
//缓存的线程池
ExecutorService cached = Executors.newCachedThreadPool();
//计划任务的线程池
ExecutorService scheduled = Executors.newScheduledThreadPool(10);
}
}
手动实现一个线程池
在自己实现的线程池中具体包含如下内容:
· 线程池的核心操作为execute,将任务加入线程池中
· 使用阻塞队列来组织所有的任务(使用的是底层为数组的阻塞队列)
· 在创建线程池时,需要初始化核心线程的数目以及阻塞队列的容量
· 利用for循环来使初始化的核心线程不断地从阻塞队列中取任务,如果阻塞队列为空就等待
具体实现代码如下
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Created with IntelliJ IDEA.
* Description: 自己模拟实现线程池
* User: Li_yizYa
* Date: 2022—05—27
* Time: 23:48
*/
public class MyThreadPool {
//线程数: 员工的数量
private int count;
//阻塞队列: 仓库
private BlockingQueue<Runnable> queue;
public MyThreadPool(int count, int capacity) {
this.count = count;
queue = new ArrayBlockingQueue<>(capacity);
//线程池创建,就创建线程来不断取任务并执行
for (int i = 0; i < count; i++) {
new Thread(new Runnable() {
@Override
public void run() {
//不停地从仓库中取任务: 如果取不到就等待
while(true) {
try {
Runnable task = queue.take();
task.run();//执行任务
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
//提交任务
public void execute(Runnable task) {
try {
queue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}