线程池的作用:
管理控制:线程池可以更好的控制线程,使我们可以对线程的生命周期、初始化、运行状态、销毁等各个环节有一个把控。
系统资源:线程池可以控制线程的数量,根据任务的多少去对线程池中的线程个数进行添加或减少,可以回收空闲状态的线程,减少线程的频繁初始化和销毁,避免不必要的系统开销,节省系统资源。保障稳定性。
应用性能:线程池可以配合高并发容器的设置,异步多线程的去处理任务,提高应用服务的吞吐率、消费性能,也提高了单个线程的利用率。
兜底策略:线程池提供了很多拒绝策略以应对很多情况。记录日志什么的。
线程池有很多重载的方法来创建线程:
这里不一一赘述了,但是一些情景中,jdk自带的这些方法并不能完全符合我们开发的要求,所以需要我们自定义线程池,这样也更灵活。
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler
);
}
自定义线程池,只需要new出来ThreadPoolExecutor对象就ok了,这个对象的构造方法很多,最全的有7个参数的构造方法,如上图。
corePoolSize:核心线程数。
maximumPoolSize:线程池最大可容纳多少个线程同时运行。
keepAliveTime:线程的存活时间,到达时间后线程就over了。
unit:时间戳,keppAliveTime的单位。
workQueue:这个队列是的作用是当线程池中线程已满,但是又有任务要运行时,就会把任务放到这个队列中。但是有界队列和无界队列是有区别的。
threadFactory:这个线程工厂就是自定义线程池任务运行的具体逻辑。
handler:这个地方一般做一些兜底策略,比如错误处理、异常处理等等,也就是当有界队列中线程已满而又有任务过来时,队列已经不能容纳任务了,就会在这个地方就行处理。
定义一个任务类:模拟任务运行的具体逻辑
public class Task implements Runnable{
private Integer id;
private Integer count;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public Task(Integer id, Integer count) {
this.id = id;
this.count = count;
}
public Task(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "当前任务的id为:" + this.id;
}
@Override
public void run() {
try {
System.err.println("任务运行:" + this.id);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
然后自定义线程池,进行测试:
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, //coresize 核心线程数
3, //maxmumPoolSize 线程池的最大上线21\
60, //线程的存存活时间
TimeUnit.SECONDS,
//new ArrayBlockingQueue<>(2),
new LinkedBlockingQueue<Runnable>(),
new ThreadFactory() { //线程工厂,用户获取一个新的线程,把该线程投递到线程池中去
@Override
public Thread newThread(Runnable r) {
Thread th = new Thread(r,"order-thread");
if(th.getPriority() != Thread.NORM_PRIORITY) {
th.setPriority(Thread.NORM_PRIORITY);
}
if(th.isDaemon()) {
th.setDaemon(false);
}
return th;
}
},
new RejectedExecutionHandler() { //拒绝策略
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("任务已经被拒绝..." + r.toString());
}
}
);
Task task1 = new Task(1);
Task task2 = new Task(2);
Task task3 = new Task(3);
Task task4 = new Task(4);
Task task5 = new Task(5);
Task task6 = new Task(6);
pool.execute(task1);
pool.execute(task2);
pool.execute(task3);
pool.execute(task4);
pool.execute(task5);
pool.execute(task6);
pool.shutdown();
}
测试结果:
1、无界队列:总会按顺序2个2个的运行,因为核心线程数是2。
2、有界队列:当超出队列容量时就会走handler。