了解下JUC的线程池学习一
1.设计者(Doug Lea)
2.ThreadPoolExecutor实现的最顶层接口
public interface Executor {
void execute(Runnable command);
}
说明:ExecutorService
提供了很多扩展方法底层基本上是基于Executor#execute()
方法进行扩展
hreadPoolExecutor
的源码从JDK8
到JDK11
基本没有变化,这里是基于JDK11的实现
3.ThreadPoolExecutor的实现原理
第一点:ThreadPoolExecutor
里面使用到JUC同步器框架AbstractQueuedSynchronizer
(俗称AQS
)、大量的位操作、CAS
操作。
第二点:ThreadPoolExecutor
提供了固定活跃线程(核心线程)、
额外的线程(线程池容量 - 核心线程数这部分额外创建的线程,下面称为非核心线程)、
任务队列以及拒绝策略这几个重要的功能。
4.线程池使用同步器的方面
第一个:全局锁mainLock
成员属性,是可重入锁ReentrantLock
类型,
主要是用于访问工作线程Worker
集合和进行数据统计记录时候的加锁操作。
第二个:条件变量termination
,Condition
类型,
主要用于线程进行等待终结awaitTermination()
方法时的带期限阻塞。
第三个:任务队列workQueue
,BlockingQueue<Runnable>
类型,
任务队列,用于存放待执行的任务。
第四个:工作线程,内部类Worker
类型,是线程池中真正的工作线程对象。
5.核心线程实现
1)要实现核心线程需要注意点:
第一点:暂时不考虑任务执行异常情况下的处理。
第二点:任务队列为无界队列。
第三点:线程池容量固定为核心线程数量。
第四点:暂时不考虑拒绝策略。
2)实现
public class CoreThreadPool implements Executor {
private static final AtomicInteger COUNTER = new AtomicInteger();
private int coreSize;
private int threadCount = 0;
this.coreSize = coreSize;
this.workQueue = new LinkedBlockingQueue<>();
}
public void execute(Runnable command) {
if (++threadCount <= coreSize) {
new Worker(command).start();
} else {
try {
workQueue.put(command);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
private Runnable firstTask;
super(String.format("Worker-%d", COUNTER.getAndIncrement()));
this.firstTask = runnable;
}
public void run() {
Runnable task = this.firstTask;
while (null != task || null != (task = getTask())) {
try {
task.run();
} finally {
task = null;
}
}
}
}
try {
return workQueue.take();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
CoreThreadPool pool = new CoreThreadPool(5);
IntStream.range(0, 10).forEach(i -> pool.execute(() ->
System.out.println(String.format("Thread:%s,value:%d", Thread.currentThread().getName(), i))));
Thread.sleep(Integer.MAX_VALUE);
}
}
take()
方法,ThreadPoolExecutor
也是类似这样实现,只是如果使用了keepAliveTime
并且允许核心线程超时allowCoreThreadTimeOut
设置为true
)则会BlockingQueue#poll(keepAliveTime)
进行轮询代替永久阻塞。maximumPoolSize
(线程池最大线程数)和corePoolSize
(核心线程数)maximumPoolSize - corePoolSize
个线程去执行新提交的任务。keepAliveTime
,keepAliveTime
。ThreadPoolExecutor#execute()
方法。private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private final BlockingQueue<Runnable> workQueue;
private final HashSet<Worker> workers = new HashSet<>();
// 全局锁
private final ReentrantLock mainLock = new ReentrantLock();
private final Condition termination = mainLock.newCondition();
private int largestPoolSize;
// 记录已经成功执行完毕的任务数
private long completedTaskCount;
// 线程工厂,用于创建新的线程实例
private volatile ThreadFactory threadFactory;
private volatile RejectedExecutionHandler handler;
// 空闲线程等待任务的时间周期,单位是纳秒
private volatile long keepAliveTime;
// 是否允许核心线程超时,如果为true则keepAliveTime对核心线程也生效
private volatile boolean allowCoreThreadTimeOut;
// 核心线程数
private volatile int corePoolSize;
private volatile int maximumPoolSize;
}
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
corePoolSize
:int类型,核心线程数量。
maximumPoolSize
:int类型,最大线程数量,也就是线程池的容量。
keepAliveTime
:long类型,线程空闲等待时间,也和工作线程的生命周期有关。
unit
:TimeUnit
类型,keepAliveTime
参数的时间单位,实际上keepAliveTime
最终会转化为纳秒。
workQueue
:BlockingQueue<Runnable>
类型,等待队列或者叫任务队列。
threadFactory
:ThreadFactory
类型,线程工厂,用于创建工作线程(包括核心线程和非核心线程),默认使用
Executors.defaultThreadFactory()
作为内建线程工厂实例,一般自定义线程工厂才能更好地跟踪工作线程。
handler
:RejectedExecutionHandler
类型,线程池的拒绝执行处理器,更多时候称为拒绝策略,
拒绝策略执行的时机是当阻塞队列已满、没有空闲的线程(包括核心线程和非核心线程)并且继续提交任务。
提供了4种内建的拒绝策略实现:
AbortPolicy
:直接拒绝策略,也就是不会执行任务,直接抛出RejectedExecutionException
,这是默认的拒绝策略。
DiscardPolicy
:抛弃策略,也就是直接忽略提交的任务(通俗来说就是空实现)。
DiscardOldestPolicy
:抛弃最老任务策略,也就是通过poll()
方法取出任务队列队头的任务抛弃,然后执行当前提交的任务。
CallerRunsPolicy
:调用者执行策略,也就是当前调用Executor#execute()
的线程直接调用任务Runnable#run()
,
一般不希望任务丢失会选用这种策略,但从实际角度来看,原来的异步调用意图会退化为同步调用。
学习:https://www.cnblogs.com/throwable/p/13574306.html