线程是稀缺资源,如果被无限制地创建,不仅会消耗系统资源,还会降低系统稳定性。合理地使用线程池对线程进行统一分配、调优和监控,有以下好处:
Java1.5引入的Executor框架把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池。而不需要关心该任务是如何执行、被哪个线程执行以及什么时候执行。
步骤如下:
实例代码:
private static Executor mExecutor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
mExecutor.execute(new Task());
}
}
static class Task implements Runnable {
@Override
public void run() {
LogUtils.e("Current Thread is named —— " + Thread.currentThread().getName());
}
}
在Java线程启动时,会创建一个本地操作系统线程,当该Java线程终止时,这个操作系统线程也会被回收。而每一个Java线程都会被一对一映射为本地操作系统的线程,操作系统会调度所有的线程并将它们分别给可用的CPU。而所谓的映射方式是这样实现的。在上层,Java多线程程序通过把应用分为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。这样两级调度模型如下图所示:
从图中我们可以看出,应用程序通过Executor框架控制上层的调度,而下层的调度由操作系统内核控制,下层的调度不受应用程序控制。
Executor框架的结构主要包括3个部分:
下面我们通过一个UML图来认识一下这些类之间的关系:
Executor是一个接口,它是Executor框架的基础,它将任务的提交和任务的执行分离开来。
ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务。
ScheduleThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。比Timer更灵活,功能更强大。
Future接口和实现了Future接口的FutureTask类,代表异步计算的结果。
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或者ScheduleThreadPoolExecutor执行。区别就是Runnable无法返回执行结果,而Callable可以返回执行结果。
下面我们通过一张图来理解它们之间的执行关系:
分析说明:
到此Executor框架的主要体系结构我们都介绍完了。接下来介绍其中比较重要的类。
Executors是java线程池的工厂类,通过它可以快速初始化一个符合业务需求的线程池。
以下为Executors类中用于创建不同线程池的常用工厂方法:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
初始化一个指定线程数的线程池,使用LinkedBlockingQueue作为阻塞队列,当没有空闲线程时,后面提交的任务将加入LinkedBlockingQueue。由于LinkedBlockingQueue是无界队列,同时corePoolSize == maximumPoolSize,所以参数maximumPoolSize和keepAliveTime无效,运行时也不会拒绝任务,可以一直添加新任务到阻塞队列中,不会调用RejectExecutionHandler的rejectExecution方法抛出异常。不过当线程没有可执行任务时,也不会释放线程。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
所以,使用该线程池时,一定要注意控制并发的任务数,否则创建大量的线程可能导致严重的性能问题。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
初始化后的线程池只有一个线程,除了这个其他与FixedThreadPoolExecutor相同。如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行,内部使用LinkedBlockingQueue作为阻塞队列,会按照提交的顺序保存在队列中。这种特点可以用来处理共享资源的问题而不需要考虑同步的问题。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
因为ScheduleThreadPoolExecutor继承了ThreadPoolExecutor,所以实际上调用的也是ThreadPoolExecutor的实现方法。
初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。
其本质上都是通过不同的参数初始化一个ExecutorService对象,newScheduledThreadPool()则为ScheduledExecutorService(这个会在后续讲解),其也是继承于ThreadPoolExecutor。
public interface ExecutorService extends Executor {
void shutdown();
List shutdownNow();
boolean isShutdown();
Future submit(Callable task);
Future submit(Runnable task, T result);
Future> submit(Runnable task);
List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException;
......
}
ExecutorService接口继承了Executor,并且提供了一些其他的方法,比如说:
shutdownNow()
:关闭线程池,返回放入了线程池,但是还没开始执行的任务submit(Callable)
:执行任务,并且有返回值invokeAll(Collection extends Callable>)
:运行把任务放进集合中,进行批量的执行,并且能有返回值这三个方法也可以说是这个接口重点扩展的方法。
另外还有shutdown()(关闭执行的任务,并且不接受新任务)、submit(Runnable, T)等方法。
PS:execute()和submit()的区别:
AbstractExecutorService是一个抽象类,主要完成了对ExecutorService接口中submit(),invokeAll()方法的实现。但是它们内部还是调用的execute()方法。
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList> futures = new ArrayList>(tasks.size());
boolean done = false;
try {
for (Callable t : tasks) {
RunnableFuture f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (int i = 0, size = futures.size(); i < size; i++) {
Future f = futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
ThreadPoolExecutor继承了AbstractExecutorService,并且实现了最重要的execute()方法,也就是说在AbstractExecutorService中的submit()和invokeAll()方法调用的就是ThreadPoolExecutor中的execute()。
ThreadPoolExecutor的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue 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;如果当前线程数为corePoolSize,继续提交的任务会被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartCoreThread()(或prestartAllcoreThreads())方法,线程池会提前创建并启动(所有)核心线程。
线程池中允许启动的最大线程数量。在核心线程全部启动的情况下,如果当前的阻塞队列满了,这时继续提交任务,则会创建新的线程执行任务,前提是当前线程数小于maximumPoolSize。
线程在空闲时的存活时间,即当线程没有任务可执行时,所能存活的时间;默认情况下,该参数只在线程数大于corePoolSize才起效。
keepAliveTime的时间单位
用来保存等待被执行的任务的阻塞队列,需要保证任务实现了Runnable接口。在JDK中提供了如下阻塞队列:
创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。
JDK中提供了一个默认的threadFactory:
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
在这个类中,有两个成员变量非常重要:
private final BlockingQueue
workQueue; private final HashSet workers = new HashSet ();
对于workers变量,存放了线程对象Worker,Worker实现了Runnable接口,而对于workQueue变量,主要存放了需要执行的任务。这样其实可以猜到,线程池的实现原理应该是从workQueue中不断地取出需要执行的任务,加入到workers中进行处理。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
其中AtomicInteger变量ctl的功能非常强大:利用低29位表示线程池中线程数,通过高3位表示线程池的运行状态:
1. RUNNING:-1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
2. SHUTDOWN: 0 << COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
3. STOP : 1 << COUNT_BITS,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;
4. TIDYING : 2 << COUNT_BITS,即高3位为010;
5. TERMINATED: 3 << COUNT_BITS,即高3位为011;
另外,当线程池中的线程都处于运行状态,多余的任务会等待,那么等待的过程是怎样实现的呢?答案是利用了BlockingQueue的take()方法进行处理。
线程池框架提供了两种提交任务的方式,根据不同的业务需求选择不同的方式。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
通过Executor.execute()方法提交的任务,必须实现Runnable接口,该方式提交的任务不能获取返回值,因此无法判断任务是否执行成功。
Future submit(Callable task);
Future submit(Runnable task, T result);
Future> submit(Runnable task);
通过ExecutorService.submit()方法提交的任务,可以获取任务的返回值。
事实上,无论是Executor.execute()或是ExecutorService.submit()方法,在它们内部实现线程任务执行的方法是同一个,即继承了AbstractExecutorService的ThreadPoolExecutor中的execute()方法。接下来就将介绍这个方法。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* 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.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
这里的代码逻辑在代码注释中解释的很清楚了。为了方便阅读,我还是对其进行翻译一下:
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
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;
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
}
}
这部分是addWorker()的前半部分
1. 判断线程池的状态,如果状态值大于或等于SHUTDOWN,则不处理提交的任务,直接返回;否则,进入步骤2
2. 通过参数core判断当前需要创建的线程是否为核心线程,如果为true,且当前线程数小于corePoolSize,则跳出循环,开始创建新的线程,具体实现如下:
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;
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;
}
线程池的工作线程通过Worker类实现,在ReentrantLock锁的保证下,把Worker实例插入到HashSet后,启动Worker中的线程,其中Worker类设计如下:
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker. */
public void run() {
runWorker(this);
}
从Worker的构造方法中可以看到:线程工厂在创建线程thread时,将Worker实例本身this作为参数传入,当执行start()方法启动线程thread时,本质是执行了Worker的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
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;
。。。。。。
} finally {
afterExecute(task, thrown);
}
。。。。。。
runWorker()是线程池的核心:
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.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
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;
}
}
}
整个getTask()操作在自循环中完成,主要操作是:
ScheduleThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后执行任务,或者定期执行任务。功能与Timer类似,但比Timer更强大,Timer对应的是单个后台线程,而ScheduleThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。
ScheduleThreadPoolExecutor使用了DelayQueue作为阻塞队列,和LinkedBlockingQueue一样,是无界队列。ScheduleThreadPoolExecutor的初始化和FixedThreadPoolExecutor等一样,实质上都是调用了ThreadPoolExecutor的初始化方法。不同的是,当调用scheduleAtFixedRate()或scheduleWithFixedDelay()方法时,会向ScheduleThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduleFuture接口的ScheduleFutureTask。
public static void startExecutor(String[] args) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
LogUtils.e("startTime = " + getFormatTime());
try {
for (int i = 0; i < 3; i++) {
// Worker worker = new Worker();
Task task = new Task();
executorService.schedule(task, 10, TimeUnit.SECONDS);
Thread.sleep(1000);
}
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
// executorService.scheduleAtFixedRate();
// executorService.scheduleWithFixedDelay();
}
executorService.shutdown();
while (!executorService.isTerminated()) {
//wait for all worker to be finished
}
LogUtils.e("All workers is finished, the time = " + getFormatTime());
}
运行结果:
线程任务确实在延迟10s后才开始执行。这就时schedule()方法的使用。
scheduleAtFixedRate()方法的作用是预定在设定的initialDelay时间结束后,周期地执行给定的任务。周期长度为period。
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 sft =
new ScheduledFutureTask(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
scheduleWithFixedDelay()方法的作用是预定在初始的延迟结束后周期地执行给定任务,不同的是在一次调用完成和下一次调用开始之间有长度为delay的延迟。
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 sft =
new ScheduledFutureTask(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(-delay)); //唯一和scheduleAtFixedRate()不同的地方
RunnableScheduledFuture t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
通过ExecutorService.submit()方法提交的任务,可以获取任务执行完的返回值
private static ExecutorService mExecutor = Executors.newFixedThreadPool(10);
public void startForResult() {
Future future = mExecutor.submit(new Task());
try {
String result = (String) future.get();
LogUtils.e("result = " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
static class Task implements Callable {
@Override
public Object call() throws Exception {
TimeUnit.SECONDS.sleep(2);
return "this is a future case";
}
}
在实际业务场景中,Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果。
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
通过submit()方法提交的Callable任务会被封装成一个FutureTask对象
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
FutureTask在不同阶段拥有不同的状态state,初始值为NEW(0)。
FutureTask类实现了Runnable接口,这样就可以通过Executor.execute()方法提交FutureTask到线程池中等待被执行,最终执行了FutureTask的run()方法,保存运行结果。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
内部通过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);
}
}
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable 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);
}
}
FutureTask.run()方法是在线程池中被执行的,而非主线程:
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
set和setException方法中,都会通过UnSAFE修改FutureTask的状态,并执行finishCompleting()方法通知主线程任务已经执行完成
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
}
深入分析java线程池的实现原理
java&android线程池-Executor框架之ThreadPoolExcutor&ScheduledThreadPoolExecutor浅析(多线程编程之三)