为什么要使用线程池?
笔者带着读者们的疑惑查阅古今著名经典:《黄帝内经》,《四书五经》,《本草纲目》,《方志鹏的spring cloud初级卷》等;
得到 诸子百家的解答:
1:系统资源有限,每个人都是手动创建线程,当系统运行起来,所有线程都在疯狂抢占资源,无组织无纪律,有可能教室就炸锅啦(这场景我学生时代历历在目);
2:开销大,又是创建又是销毁(底层原理俺不懂-_-);
到此,知道了为什么,理解东西就更深刻了。
经过查阅当代所有文献,以及笔者对所有同行同事的跪舔以及不耻下问,得出,使用这个玩意儿:ThreadPoolExecutor。Java线程池就是为了最大化高并发带来的性能提升,并最小化手动创建线程的风险,将多个线程统一在一起管理。
上代码:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;
maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
keepAliveTime:当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;
unit:keepAliveTime的单位
workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种;
threadFactory:线程工厂,用于创建线程,一般用默认即可;
handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务;
以上参数配置不作详细介绍,里面配置类型很多,各位自行查阅(主要是小弟棋艺不精~~)
来例子:
案例1:三个线程,最大线程数是4,先执行第一个线程,进入睡眠,然后执行新建第二个线程
package com.china.great.amos.chinagreatblog.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Liu HongYang
* @DateTime: 2020/5/18 10:55 下午
* @Description: TODO
*/
public class ThreadPools {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));
// 第1个任务
pool.execute(() -> {
try {
Thread.sleep(5 * 1000);// 5秒
System.out.println("--001--" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 第2个任务
pool.execute(() -> System.out.println("--002--" + Thread.currentThread().getName()));
// 第3个任务
/* pool.execute(() -> System.out.println("--003--" + Thread.currentThread().getName()));
// 第4个任务
pool.execute(() -> System.out.println("--004--" + Thread.currentThread().getName()));
// 第5个任务
pool.execute(() -> System.out.println("--005--" + Thread.currentThread().getName()));*/
}
}
结果为:
案例2:一共两个线程,最大是3,队列数是2,001跟002一开始就占满了两个核心线程,线程003跟线程0044就进入了队列,所以先执行完线程0022,然后执行队列里面的003跟004,最后是001
package com.china.great.amos.chinagreatblog.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Liu HongYang
* @DateTime: 2020/5/18 10:55 下午
* @Description: TODO
*/
public class ThreadPools {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));
// 第1个任务
pool.execute(() -> {
try {
Thread.sleep(5 * 1000);// 5秒
System.out.println("--001--" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 第2个任务
pool.execute(() -> {
try {
Thread.sleep(4 * 1000);// 5秒
System.out.println("--002--" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 第3个任务
pool.execute(() -> System.out.println("--003--" + Thread.currentThread().getName()));
// 第4个任务
pool.execute(() -> System.out.println("--004--" + Thread.currentThread().getName()));
// 第5个任务
/*pool.execute(() -> System.out.println("--005--" + Thread.currentThread().getName()));*/
}
}
结果:
案例3:把参数LinkedBlockingQueue改为1,主要是因为一共只有两个线程,001跟002马上占满,队列只允许1个,003进入队列,实际运行线程=2,小于maximumPoolSize最大线程数3,所以004新开一个线程
结果为: