线程池:三大方法 7大参数 4种拒绝策略
线程池的好处:
降低资源的消耗
提高响应的速度
方便管理
线程复用、控制最大并发数、管理线程
三大方法
一般不用Executors工具类创建线程池,不安全
public class ToolMethods {
public static void main(String[] args) {
//1. 单个线程
//ExecutorService threadPool = Executors.newSingleThreadExecutor();
//2. 创建一个固定的线程池的大小
//ExecutorService threadPool = Executors.newFixedThreadPool(5);
//3. 可伸缩的,遇强则强,遇弱则弱
ExecutorService threadPool = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
//使用线程池创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,关闭线程池
threadPool.shutdown();
}
}
}
7大参数:ThreadPoolExecutor的7个构造参数
源码
创建方法1:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
创建方法2:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
创建方法3:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
7大参数
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;
}
手动创建一个线程池:
为方便7大参数的理解,进行场景举例
场景举例:银行办理业务
银行共有5个窗口,–maximumPoolSize
长期提供服务的有两个,–corePoolSize
候客区可以容纳3个客户,-- new LinkedBlockingQueue<>(3)
如果客户数量超过了窗口总数5,那么按需相继打开其他三个窗口,
如果候客区满了还有人进来就启动拒绝策略,–4大拒绝策略 拒绝策略的触发条件是客户数量超过了窗口总数加队列容量的和
客户减少到少于5个,有的窗口长期闲置,闲置超过3S就关闭窗口–keepAliveTime TimeUnit.SECONDS
public class CustomThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
//4大拒绝策略
//策略一:不处理,抛出异常
new ThreadPoolExecutor.AbortPolicy()
//策略二:从哪来回哪去,从主线程来就让主线程处理一起加入处理任务
// new ThreadPoolExecutor.CallerRunsPolicy()
//策略三:队列满了尝试和最早的竞争,如果竞争失败就会丢掉,也不会抛出异常
// new ThreadPoolExecutor.DiscardOldestPolicy()
//策略四:队列满了不抛出异常,但会丢掉任务
// new ThreadPoolExecutor.DiscardPolicy()
);
try {
//调整i控制客户数量
for (int i = 1; i <= 15; i++) {
final int temp = i;
//使用线程池创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" ok"+temp);
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,关闭线程池
threadPool.shutdown();
}
}
}
4种拒绝策略
策略一:不处理,抛出异常
new ThreadPoolExecutor.AbortPolicy()
策略二:从哪来回哪去,从主线程来就让主线程处理一起加入处理任务
new ThreadPoolExecutor.CallerRunsPolicy()
策略三:队列满了尝试和最早的竞争,如果竞争失败就会丢掉,也不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy()
策略四:队列满了不抛出异常,但会丢掉任务
new ThreadPoolExecutor.DiscardPolicy()
如何设置池的大小
1.CPU密集型 电脑cpu核数,保证cpu效率最高 == Runtime.getRuntime().availableProcessors()
2.IO密集型 判断程序中十分消耗IO的线程数量,大于这个数量即可 可以是2倍