并发编程(一)Executor
1.1. 为什么需要线程池?
线程池是一个重量级别的对象,所以应该避免频繁的创建和销毁。
- 创建一个线程不仅仅需要在jvm的堆里边分配一块内存,还需要调度操作系统内核的api,操作系统需要给线程分配一系列的资源。
线程池解决的问题:解决线程的频繁创建和销毁。
1.2. 线程池是什么
线程池就是一个创建线程的池子,但是它不同于我们常见的池化资源。线程池是一个生产者消费者模式的池子。
生产者: 使用方
消费者:线程池
这里需要提到的一点是,虽然java给我们提供了Executors这个工具类,用起来很方便,但是不建议使用,因为Executors的方法里边大部分的工作队列为一个无界队列,容易造成oom。建议使用ThreadPoolExecutor来自己创建线程池。
exmple:
/**
*
* @author:
* @Date: 2019-06-26 16:52
* @Copyright: 2019 www.lenovo.com Inc. All rights reserved.
*/
public class TestThreadPool {
private static int CORE_POOL_SIZE =10;
private static int MAX_POOL_SIZE = 11;
private static int QUEUE_SIZE = 100;
private static long KEEP_ALIVE_TIME =10;
private static ThreadFactory factory = new ThreadFactory() {
private final AtomicInteger integer = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "zy test thread: " + integer.getAndIncrement()); }
};
private static class SingleThreadPool{
private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAX_POOL_SIZE,KEEP_ALIVE_TIME, TimeUnit.SECONDS,new LinkedBlockingDeque<>(QUEUE_SIZE));
}
public static ThreadPoolExecutor getInstance(){
return SingleThreadPool.THREAD_POOL_EXECUTOR;
}
}
1.3 Executors线程池的核心参数
- corePoolSize(int)
- 核心线程数量或者叫做最小线程数量
- maximumPoolSize(int)
- 最大线程数量,线程池允许存在的最大线程数量
- keepAliveTime(long)
- 最大空闲时间,当一个线程空闲的时间大于keepAliveTime并且此时线程池中corePoolSize>maximumPoolSize当前线程就会被回收
- unit(TimeUnit)
- 空闲时间的单位
- workQueue BlockingQueue
- 工作队列
- threadFactory (ThreadFactory)
- 自定义线程的信息,如上边的代码就是定义了没个线程的名称。
- handler(RejectedExecutionHandler)
- 拒绝策略 ,触发条件,线程的工作队列满了(工作队列是有界队列),并且线程池中所有的线程也都在执行任务,就会触发线程的拒绝策略。
- CallerRunsPolicy:完成完任务的线程 自动去执行该任务。
- AbortPolicy:默认,抛出 RejectedExecutionException异常
- DiscardOldestPolicy: 丢弃最老的任务,把最早加入到工作队列中的任务丢弃。
- 拒绝策略 ,触发条件,线程的工作队列满了(工作队列是有界队列),并且线程池中所有的线程也都在执行任务,就会触发线程的拒绝策略。