1.线程池
线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务
2.池化技术
程序的运行的本质:占用系统的资源!优化资源的技术 ===> 池化技术。
为什么使用:线程池、连接池、内存池、对象池。。。。创建、销毁。十分浪费资源
池化技术:事先准备好一些资源,有人要用,就来池子里拿,用完之后还过来。
线程池的好处:
-
降低资源的浪费
-
提高响应的速度
-
方便管理。
3. 三大方法
public class ExecutorsDemo {
public static void main(String[] args) {
// Executors 工具类、3大方法
// 1.ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
// 2.ExecutorService threadPool = Executors.newFixedThreadPool(5);// 创建一个固定的线程池的大小
//3.ExecutorService threadPool = Executors.newCachedThreadPool();// 可伸缩的,遇强则强,遇弱则弱
ExecutorService threadPool = Executors.newCachedThreadPool();// 可伸缩的,遇强则强,遇弱则弱
try {
for (int i = 1; i <= 100; i++) {
// 使用了线程池之后,使用线程池类创建线程
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "---OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
}
4.七大参数
Executors 工具类提供的三种方法本质是调用ThreadPoolExecutor()。通过设置其中的7种参数来定义线程池。
// 本质ThreadPoolExecutor()
public ThreadPoolExecutor(int corePoolSize, // 核心线程池大小
int maximumPoolSize, // 最大核心线程池大小
long keepAliveTime, // 超时没有人调用就会释放
TimeUnit unit, // 超时单位
BlockingQueue<Runnable> workQueue, // 阻塞队列
ThreadFactory threadFactory, //线程工厂:创建线程的,一般不用动
RejectedExecutionHandler handler) { //拒绝策略
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
5.四种拒绝策略
1.new ThreadPoolExecutor.AbortPolicy() // 队列满了,还有线程进来,不处理这个线程的,抛出异常
2.new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
3.new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
4.new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常
6.自定义线程池
举例,银行共有5个窗口(最大线程数),有常开的两个窗口处理业务(核心线程数);候客区(阻塞队列)有三个位置;当两个常开窗口(核心线程)以及候客区(阻塞队列)的位置都有人后,再来客户会开启另外三个窗口;当5个窗口(最大线程)和候客区(阻塞队列)都有人后,再来客户会启动拒绝策略。当窗口(线程)超过设定时间(超时时间)没有业务办理时(未调用)会关闭窗口(释放线程)。
public class ExecutorsDemo01 {
public static void main(String[] args) {
// 自定义线程池!工作ThreadPoolExecutor
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()); //队列满了,尝试去和 最早的竞争,也不会抛出异常!
try {
// 最大承载:Deque + max
// 超过 RejectedExecutionException
for (int i = 1; i <= 9; i++) {
// 使用了线程池之后,使用线程池来创建线程
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
}
7.拓展
问题:池的线程最大值如何去设置!
1、CPU 密集型,几核的计算机就设置为几,可以保存CPU的效率最高!
自动获取计算机CPU处理器个数Runtime.getRuntime().availableProcessors()
2、IO 密集型 —> 判断程序中十分耗IO的线程,根据IO线程数来设定。
比如:15个大型IO线程任务,可以最大线程数为30