java线程池原理简要说明
java线程池(ThreadPoolExecutor)源码解析一
excecute()
reject(command)
java线程池(ThreadPoolExecutor)源码解析二
addWorker()
为什么workers使用HashSet和ReentraintLock而不使用并发的set
java线程池(ThreadPoolExecutor)源码解析三
ctl成员变量
java线程池(ThreadPoolExecutor)源码解析四
getTask()
线程池使用如下
public static void main(String[] args) {
int coreSize = 1;//核心线程数
int maxSize = 2;//最大线程数
long keepAliveTime = 10;//临时线程空闲时间
TimeUnit unit = TimeUnit.MINUTES;//临时线程空闲时间单位
BlockingQueue<Runnable> blockQueue = new LinkedBlockingQueue<Runnable>();//用于存任务的阻塞队列
RejectedExecutionHandler handler = new RejectedExecutionHandler() {//任务队列满了以后对不能入队的任务的处理策略
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("线程池已满");
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, maxSize, keepAliveTime, unit, blockQueue,
handler);
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
}
});
}
executor.shutdown();
}
excecute()方法
可以看出核心方法是execute() 方法,下面是加了注释的execute()方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
*
* 1. 如果线程数小于核心线程数,则启动一个新的线程,并将传入的runable作为他的第一个任务。
* addWorker()方法自动检查线程池运行状态和工作线程数,如果当前状态不应该再启动新的线程,
* addwoker()返回false
*
* 2. 如果一个task成功进入队列,还是要再检查一次是否需要创建一个新的线程(因为在上一次检查后,
* 之前存活的线程的生命周期可能已经结束了),或者进入这个方法之后线程池被关闭了。因此重新检查状态,
* 根据情况来决定是移除任务还是再创建一个线程
*
* 3. 如果不能将任务放入队列,就尝试再启动一个新的线程。如果失败了,那就说明线程池关闭了或者线程池满了,
* 所以后面执行拒绝策略
*/
int c = ctl.get(); //ctl 是一个 AtomicInteger,用来存线程池的状态和工作线程数量,以后会说明
if (workerCountOf(c) < corePoolSize) { //workerCountOf(c) 方法获取线程池已有线程数量
if (addWorker(command, true)) //addWoker方法尝试创建新的线程执行任务
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
/*下面又进行了一次检查,主要是防止这种情况:线程A执行完上面的isRunning,返回运行中,然后挂起。
* 这时候线程B调用了shutdown,关闭了线程池,这时候如果成功将线程池内所有线程结束了,这是线程A继续执行
* workQueue.offer(command) 将任务入队,如果没有下面的第二次检查,这个任务将漏掉,既没有执行run方法,
* 也没有执行拒绝策略
*/
if (! isRunning(recheck) && remove(command))//isRunning(recheck) 返回当前线程的状态是否是运行中
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command); //reject方法很简单就是调用了传入的 rejectExcetpionHandler
}
reject(command)方法
/**
* Invokes the rejected execution handler for the given command.
* Package-protected for use by ScheduledThreadPoolExecutor.
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}