分析线程池前最好先了解下阻塞队列:java多线程系列15-阻塞队列
1.线程池
线程池大家平时都经常使用,使用线程池有什么好处:
- 降低资源的消耗。降低线程创建和销毁的资源消耗
- 提高响应速度:线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间
- 提高线程的可管理性
2.ThreadPoolExecutor
ThreadPoolExecutor,jdk所有线程池实现的基础。
2.1重要参数含义
int corePoolSize:线程池中核心线程数,< corePoolSize,就会创建新线程,= corePoolSize ,这个任务就会保存到BlockingQueue,如果调用prestartAllCoreThreads方法就会一次性的启动corePoolSize 个数的线程。
int maximumPoolSize, 允许的最大线程数,BlockingQueue也满了,< maximumPoolSize时候就会再次创建新的线程
long keepAliveTime, 线程空闲下来后,存活的时间,这个参数只在> corePoolSize才有用
TimeUnit unit, 存活时间的单位值
BlockingQueue workQueue, 保存任务的阻塞队列
ThreadFactory threadFactory, 创建线程的工厂,给新建的线程赋予名字
RejectedExecutionHandler handler :饱和策略
AbortPolicy :直接抛出异常,默认;
CallerRunsPolicy:用调用者所在的线程来执行任务
DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务
DiscardPolicy :当前任务直接丢弃
实现自己的饱和策略,实现RejectedExecutionHandler接口即可
线程池状态:
Running:接收新任务并且处理进入阻塞队列的任务。
SHUTDOWN:不接受新任务,但处理进入阻塞队列的任务。
STOP:不接受任务,不处理进入阻塞队列的任务并且中断正在执行的任务。
TIDYING:所有的任务都已经终止,workerCount为0,线程转化为TIDYING状态并且调用terminated钩子函数。
TERMINATED:terminated钩子函数已经运行完成。
2.2 execute方法
该方法不需要返回值
(1)execute
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//如果当前线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果线程池还在运行并且command加入队列成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//再次检查,如果线程池不再处于运行状态,删除任务成功
if (! isRunning(recheck) && remove(command))
//拒绝任务
reject(command);
//如果线程池还在运行,任务加入队列成功,但线程数量为0,启动一个线程
//或者如果线程池不处于运行,任务删除失败(有其他线程把任务执行了)
else if (workerCountOf(recheck) == 0)
//第二个参数为true代表占用corePoolSize,false占用maxPoolSize
addWorker(null, false);
}
//线程池如果处于shutdown以上状态,这时候addWorker肯定不成功
//线程池还在运行,阻塞队列已经满,占用maxPoolSize数量,增加任务
else if (!addWorker(command, false))
//如果失败拒绝任务
reject(command);
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
}
execute方法可以线程池执行的主流程:
- 如果线程池中线程数量小于核心线程池数量,增加线程执行任务
- 如果到达核心线程数量,加入阻塞队列
- 如果阻塞队列已满,再次增加线程数量执行任务
- 如果线程数量到达线程最大数量,拒绝任务
(2)addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
//当前线程的状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
//如果线程状态大于SHUTDOWN或者处于SHUTDOWN时,需要添加任务,返回失败
//如果处于SHUTDOWN时,不需要添加任务,队列为空,返回失败
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
//线程数量超出范围,添加失败
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//增加worker数量
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
//线程池状态发生变化,重试
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
//加锁是为保证worker数量是线程按照的
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
//
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
//线程池曾经已有线程的最大数量
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
addWorker实际就是增加线程数量,代码前面部分都是判断
- 如果线程池目前已经处于shutdown及以上状态,不能向线程池添加任务。如果线程池处于shutdown,队列为空,不添加任务,只增加线程也不可以
- 如果预计增加的是核心线程,但核心线程数量已满,失败。如果增加的不是核心线程,但数量数量已经到达最大值,失败
- 如果以上判断通过,创建worker,启动线程执行任务
(3)addWorkerFailed方法
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
addWorkerFailed是增加线程失败后,从workers中去除,减少worker数量,尝试中断线程池
(4)tryTerminate方法
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//线程池正在运行,不能终止
//或者所有任务都已经结束,不需要终止
//线程池为SHUTDOWN并且工作队列不为空,不能终止
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//进入到这一步,只有两种情况:线程池为SHUTDOWN并且工作队列为空或者线程池为stop
//如果这时候线程池数量不为空,尝试中断一个空闲线程
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//将线程池状态设为TIDYING状态,准备调用钩子函数
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
//将线程池状态设为TERMINATED状态,调用钩子函数结束
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
tryTerminate方法是尝试中断线程,如果条件不满足,不中断或者减少一个空闲线程。如果以上条件不满足,工作队列夜空了,正式开始终止线程。
(5)interruptIdleWorkers
中断空线程首先要获得锁,因为正在执行的任务会持有锁
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
//如果获取尝试中断线程
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
//只终止一个线程
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
(6)线程执行run方法
public void run() {
runWorker(this);
}
(7)runWorker方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//释放锁后,线程可以被中断
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//如果传入任务不为空或者可以从工作队列获取任务
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
//线程池状态大于等于STOP,需要中断当前线程
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
//重置线程中断信号
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行任务
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
(8)getTask方法从阻塞队列取任务
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
//线程池状态大于SHUTDOWN,或者处于SHUTDOWN工作队列为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//减少worker数量
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果线程数量超过核心线程数或者线程任务取任务超时,并且队列为空或者线程数量大于1,尝试减少worker数量
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//从工作队列获取任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
//获取任务超时
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
(9)processWorkerExit
work结束时执行内容:尝试终止线程池或者线程池还需运行,判断是否需要增加线程
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
//异常中断,减少worker数量
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//统计完成任务数量
completedTaskCount += w.completedTasks;
//移除work
workers.remove(w);
} finally {
mainLock.unlock();
}
//尝试中断线程
tryTerminate();
int c = ctl.get();
//线程池状态处于中断及以下
if (runStateLessThan(c, STOP)) {
//如果线程非异常中断
if (!completedAbruptly) {
//线程池应该拥有的最小线程数量
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
//线程池数量足够
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//线程异常中断或者线程池数量不够,增加线程
addWorker(null, false);
}
}
(10)shutdown方法
设置线程池的状态,只会中断所有没有执行任务的线程。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//判断调用者是否有权限关闭现场
checkShutdownAccess();
//循环设置线程池状态为shutdown
advanceRunState(SHUTDOWN);
//中断所有空闲线程,只是打个标记
interruptIdleWorkers();
//钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
//尝试中断线程
tryTerminate();
}
(11)shutdownNow方法
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//判断停止线程池权限
checkShutdownAccess();
//线程池状态设为STOP
advanceRunState(STOP);
//中断所有线程
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
2.3 submit方法
平时我们用线程池submit和execute不同点是submit方法有返回值。但在ThreadPoolExecutor中我们没有看到submit方法。
执行上在execute中线程执行runWorker给我们提供了两个钩子函数: beforeExecute(wt, task)和afterExecute(task, thrown)方法。我们可以在afterExecute中进行实现取的返回值,比如:
class ExtendedExecutor extends ThreadPoolExecutor {
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}}
2.4 handler
handler: 当queue满了和线程数达到最大限制,对于继续到达的任务采取的策略。默认采取AbortPolicy , 也就是拒绝策略。
- AbortPolicy:默认的拒绝策略,当继续有任务到来时直接抛出异常
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
-
DiscardPolicy:rejectedexecution是个空方法,意味着直接抛弃该任务,不处理。
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }/** * Does nothing, which has the effect of discarding task r. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { }
}
-
DiscardOldestPolicy:除非调用了shutdown方法,否则。抛弃queue中的第一个任务,再次执行该任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
- CallerRunsPolicy:直接由执行该方法的线程继续执行该任务,除非调用了shutdown方法,这个任务才会被丢弃,否则继续执行该任务会发生阻塞。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
总结,线程池的执行步骤如图所示:
3. Executors
Executors中提供了几种不同的线程池。
3.1 FixedThreadPool
创建固定线程数量的,适用于负载较重的服务器,使用了无界队列(其实还是有界,只有最大值很大,Integer.MAX_VALUE)。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
3.2 SingleThreadExecutor
创建单个线程,需要顺序保证执行任务,不会有多个线程活动,使用了无界队列。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
3.3 CachedThreadPool
会根据需要来创建新线程的,执行很多短期异步任务的程序,使用了SynchronousQueue。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3.4 WorkStealingPool
基于ForkJoinPool实现。
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
4. ScheduledThreadPoolExecutor
这里说下另外一个具有定时执行任务功能的线程池。
newSingleThreadScheduledExecutor:只包含一个线程,只需要单个线程执行周期任务,保证顺序的执行各个任务
newScheduledThreadPool 可以包含多个线程的,线程执行周期任务,适度控制后台线程数量的时候
方法说明:
schedule:只执行一次,任务还可以延时执行
scheduleAtFixedRate:提交固定时间间隔的任务
scheduleWithFixedDelay:提交固定延时间隔执行的任务
ScheduledThreadPoolExecutor也是基于ThreadPoolExecutor实现的线程池,只是有定时功能,队列也是用了类似优先级队列的思想,没加入一个队列会进行排序,按照延迟时间最短的排序在头部。
4.1 FutureTask
定时任务中内部任务类ScheduledFutureTask继承了FutureTask,这里简单介绍下:
(1)FutureTask的状态
NEW:表示这是一个新的任务,或者还没有执行完的任务,是初始状态。
COMPLETING:表示任务执行结束(正常执行结束,或者发生异常结束),但是还没有将结果保存到outcome中。是一个中间状态。
NORMAL:表示任务正常执行结束,并且已经把执行结果保存到outcome字段中。是一个最终状态。
EXCEPTIONAL:表示任务发生异常结束,异常信息已经保存到outcome中,这是一个最终状态。
CANCELLED:任务在新建之后,执行结束之前被取消了,但是不要求中断正在执行的线程,也就是调用了cancel(false),任务就是CANCELLED状态,这时任务状态变化是NEW -> CANCELLED。
INTERRUPTING:任务在新建之后,执行结束之前被取消了,并要求中断线程的执行,也就是调用了cancel(true),这时任务状态就是INTERRUPTING。这是一个中间状态。
INTERRUPTED:调用cancel(true)取消异步任务,会调用interrupt()中断线程的执行,然后状态会从INTERRUPTING变到INTERRUPTED。
(1)run方法
public void run() {
//线程还没运行或者线程运行还没结束
//线程执行者设为自己
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
//设置结果
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
//如果线程处于正在中断还未结束,需要等待线程中断结束
handlePossibleCancellationInterrupt(s);
}
}
(2)finishCompletion
private void finishCompletion() {
// assert state > COMPLETING;
//唤醒等待结果线程
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//执行钩子函数
done();
callable = null; // to reduce footprint
}
(3)awaitDone方法
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
4.2 FutureTask
(1)构造函数
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
(2)再看下只执行一次方法schedule
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
//方法返回的就是传入的第二个值ScheduledFutureTask
//ScheduledFutureTask构造函数的triggerTime值是为后续排序准备
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
//如果线程池没有shutdown话,将任务加入队列,并且预先启动足够多的线程
delayedExecute(t);
return t;
}
(3)delayedExecute方法
private void delayedExecute(RunnableScheduledFuture<?> task) {
//线程是否在运行,没有在运行拒绝加入队列
if (isShutdown())
reject(task);
else {
//任务加入队列
super.getQueue().add(task);
//线程不再运行,需要判断在当前状态下任务是否可以继续运行
//如果不可以,从阻塞队列删除任务
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
//任务设置为取消
task.cancel(false);
else
//预先启动足够线程
ensurePrestart();
}
}
(4)scheduleAtFixedRate方法
提交固定时间间隔的任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
看上去好像和上边执行一次方法没有什么区别,看不出来怎么周期性运行,其实周期执行关键在任务的run方法。
(5)ScheduledFutureTask的run方法
public void run() {
//是否需要周期执行
boolean periodic = isPeriodic();
//当前线程状态是否可以执行任务
if (!canRunInCurrentRunState(periodic))
//不能周期性执行,取消任务
cancel(false);
else if (!periodic)
//不需要周期性执行任务,运行一次
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
//任务执行完毕,并且并未取消或者中断
//设值下一次执行时间
setNextRunTime();
//把当前任务再次加入队列
reExecutePeriodic(outerTask);
}
}
(6)reExecutePeriodic方法
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
//当前线程如果可以运行任务
if (canRunInCurrentRunState(true)) {
//任务加入队列
super.getQueue().add(task);
//如果线程不能运行取消任务
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
//确保有足够线程执行任务
ensurePrestart();
}
}
(7)scheduleWithFixedDelay方法
提交固定延时间隔执行的任务
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (delay <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(-delay));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
这时候又是不是又有点疑惑了,这个和执行固定时间间隔的区别在哪,其实是在设置下一次执行时间上。
(8)setNextRunTime
private void setNextRunTime() {
long p = period;
//p大于0,代表固定时间间隔
//p小于0,代表固定延迟间隔
if (p > 0)
//上次开始时间加上时间间隔
time += p;
else
//当前时间加上时间间隔
time = triggerTime(-p);
}
5.线程池大小
根据任务的性质来:计算密集型(CPU),IO密集型,混合型
计算密集型:加密,大数分解,正则……., 线程数适当小一点,最大推荐:机器的Cpu核心数+1,为什么+1,防止页缺失,(机器的Cpu核心=Runtime.getRuntime().availableProcessors()?
IO密集型:读取文件,数据库连接,网络通讯, 线程数适当大一点,机器的Cpu核心数*2,
混合型:尽量拆分,IO密集型>>计算密集型,拆分意义不大,IO密集型~计算密集型
队列的选择上,应该使用有界,无界队列可能会导致内存溢出,OOM
6.ExecutorCompletionService
ExecutorCompletionService实际上只是做了一次封装,内部有个阻塞队列封装了已经完成的任务,主要利用FutureTask完成时的钩子函数done方法,将完成的任务放入队列。
这样防止在原有线程中,因为中间一个线程执行时间比较长,导致后续已经完成的任务无法取得结果。
public ExecutorCompletionService(Executor executor) {
if (executor == null)
throw new NullPointerException();
this.executor = executor;
this.aes = (executor instanceof AbstractExecutorService) ?
(AbstractExecutorService) executor : null;
this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}