七、线程池:
线程池:三大方法、7大参数、4种拒绝策略
1、池化技术
2、线程池相关API:
3、三大方法:
阿里巴巴手册对线程池强制要求
// Executors 工具类、3大创建线程的方法 利用该工具类来创建线程池
public class Demo01 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
// ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定的线程池的大小
// ExecutorService threadPool = Executors.newCachedThreadPool(); // 可伸缩的,遇强则强,遇弱则弱
try {
for (int i = 0; i < 100; i++) {
// 使用了线程池之后,使用线程池来创建线程
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
}
4、七大参数
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// 本质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;
}
七大参数的含义
- int corePoolSize, // 核心线程池大小,平时正常在用的线程数
- int maximumPoolSize, // 最大核心线程池大小,当阻塞队列满了,核心线程满了后触发
- long keepAliveTime, // 超时了没有人调用就会释放 (当非核心线程空闲了,没有被调用了,前面核心线程可以解决一切问题了,就会释放那些非核心线程)
- TimeUnit unit, // 超时单位
- BlockingQueue workQueue, // 阻塞队列
- ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动
- RejectedExecutionHandler handle // 拒绝策略
银行例子:
解释:
核心线程数10,最大线程数30,keepAliveTime是3秒
随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,
这时多余的任务通过加入阻塞队列来运行,
当任务个数超出阻塞队列长度+核心线程数时,
这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30
那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,有以下四种策略
5、四种拒绝策略
/**
* new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异常
* new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!比如main线程进来的,在线程池中最大线程数加队列最大数满了,就返回给main线程去执行
* new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
* new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
*/
6、自定义线程池
package com.kuang.pc;// Executors 工具类、3大方法
import java.util.concurrent.*;
/**
四种拒绝策略
* new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异
* 常
* new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
* new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
* new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会
* 抛出异常!
七大参数:
* int corePoolSize, // 核心线程池大小,平时正常在用的线程数
* int maximumPoolSize, // 最大核心线程池大小,当阻塞队列满了,核心线程满了后触发
* long keepAliveTime, // 超时了没有人调用就会释放 (当非核心线程空闲了,没有被调用了,前面核心线程可以解决一切问题了,就会释放那些非核心线程)
* TimeUnit unit, // 超时单位
* BlockingQueue<Runnable> workQueue, // 阻塞队列
* ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动
* RejectedExecutionHandler handle // 拒绝策略)
*/
public class Demo01 {
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、池的最大的大小
了解:IO密集型,CPU密集型:(调优)
package com.kuang.pool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
// Executors 工具类、3大方法
/**
* new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异常
* new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!比如main线程进来的,在线程池中最大线程数加队列最大数满了,就返回给main线程去执行
* new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
* new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
*/
public class Demo01 {
public static void main(String[] args) {
// 自定义线程池!工作 ThreadPoolExecutor
// 最大线程到底该如何定义
// 1、CPU 密集型,几核,就是几,可以保持CPu的效率最高!
// 2、IO 密集型 > 判断你程序中十分耗IO的线程,
// 程序 15个大型任务 io十分占用资源!
// 获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());
List list = new ArrayList();
ExecutorService threadPool = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
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();
}
}
}