查询过程:百度了很多资料,很多博客上也有说实现原理,
包括状态解答
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; 任务已中断
包括功能定义
public class FutureTask implements RunnableFuture
public interface RunnableFuture extends Runnable, Future
Runnable功能定义:用来实现线程运行
Future功能定义:用来实现线程结果获取
以上可以发现,我们的疑问解答方向,主要就在Future接口里
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
接口东西不多,包括获取状态,获取结果,以及延迟等待时间,我们主要看get方法
/**
* 这里是FutureTask的get实现,
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
总结就是:在没有达到退出状态时,等待获取结果,否则返回异常或者结果。
那么,FutureTask是如何等待的呢?分为一直等待(Thread.yield())和超时等待(LockSupport.parkNanos(this, parkNanos))两种实现:
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
long startTime = 0L;
WaitNode q = null;
boolean queued = false;
//这里的无限循环,是为了状态变化唤醒线程时,不至于漏掉状态,思路清奇!
for (;;) {
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING)
// We may have already promised (via isDone) that we are done
// so never return empty-handed or throw InterruptedException
Thread.yield();
else if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
else if (q == null) {
if (timed && nanos <= 0L)
return s;
q = new WaitNode();
}
else if (!queued)
queued = U.compareAndSwapObject(this, WAITERS,
q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) { // first time
startTime = System.nanoTime();
if (startTime == 0L)
startTime = 1L;
parkNanos = nanos;
} else {
long elapsed = System.nanoTime() - startTime;
if (elapsed >= nanos) {
removeWaiter(q);
return state;
}
parkNanos = nanos - elapsed;
}
// nanoTime may be slow; recheck before parking
if (state < COMPLETING)
LockSupport.parkNanos(this, parkNanos);
}
else
LockSupport.park(this);
}
}
那么问题来了,如何在得到结果时唤醒线程呢?
下面这个方法能解答,核心思路是,采用乐观锁验证,通过唤醒线程,让get锁定的线程出结果。
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, 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
}
乐观锁实现:private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
小tips:安卓主线程会不会被get搞出anr呢? 结果是不会,但是我放在activity的create方法中,会导致界面黑60秒,没有反应,但是出现了: Choreographer: Skipped 3543 frames! The application may be doing too much work on its main thread. 通知我,主线程不是你乱搞的地方!emmmm.....
没有anr但是界面确实堵住了,猜想anr是线程忙到不行的提示,不是闲到不行的提示!
测试代码:
private void onFetureTaskTest(){
Log.d("FutureTask","任务开始时间:"+ DateUtil.getStringForMillis(Calendar.getInstance().getTimeInMillis(),DateUtil.DATE_YMDHMS));
//todo 类型要一致
Callable callable = new Callable() {
@Override
public String call() throws Exception {
Log.d("FutureTask","任务开始,等待60秒");
Thread.sleep(60_000);
Log.d("FutureTask","任务完成,返回结果");
return "10";
}
};
FutureTask taskFor = new FutureTask(callable){
@Override
protected void done() {
//自定义线程任务执行完之后的一些逻辑
super.done();
}
};
Thread thread = new Thread(taskFor);
thread.start();
try {
Log.d("FutureTask","任务完成,返回结果:"+taskFor.get());
Log.d("FutureTask","任务完成时间:"+ DateUtil.getStringForMillis(Calendar.getInstance().getTimeInMillis(),DateUtil.DATE_YMDHMS));
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
//会不会anr呢?没有anr,但是会导致页面一直延迟启动(根据后台FutureTask的执行时间来订阅启动时间)
}
好了,到这里问题就解决了,不知道看完的同学还有哪些想法,评论留言告诉我哈!别客气!