Question: Thread execution time, execution order is not controllable, so how does FutureTask get a certain return value in uncertainty?
Search process: Baidu has a lot of information, many blogs are also said to achieve the principle, including state solution
private static final int NEW = 0; Private static final int 实 实 = 1; Private static final int NORMAL = 2; Private static final int exception = 2; Private static final int CANCELLED = 4; Private static final int Interrupt = 5; Private static final int INTERRUPTED = 6; Task interruptedCopy the code
Including functional definitions
public class FutureTask<V> implements RunnableFuture<V> public interface RunnableFuture<V> extends Runnable, The Future<V> Runnable function is used to enable the thread to run the FutureCopy the code
As can be seen from the above, our question solving direction is mainly in the Future interface
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code
There’s not a lot of interface stuff, including getting state, getting results, and latency, but we’ll focus on the GET method
*/ public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
Copy the code
The summary is: if the exit state is not reached, wait for the result, otherwise return an exception or result.
So how does FutureTask wait? There are two implementations, thread.yield () and timeout wait (locksupport.parknanos (this, parkNanos)) :
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
long startTime = 0L;
WaitNode q = null;
boolean queued = false; // This loop is used to wake up threads for state changes.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);
}
elseLockSupport.park(this); }}Copy the code
So, how do you wake up the thread when you get the result?
The following method can solve the problem, the core idea is to use optimistic lock validation, by waking up the thread, let the thread get locked results.
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; // Wake up the thread locksupport. unpark(t); } WaitNode next = q.next;if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break; }} // This method can be self-implemented,done(a); callable = null; // to reduce footprint }Copy the code
Optimistic locking implementation: private static final sun. Misc. Unsafe U = sun. Misc. Unsafe. GetUnsafe ();
Will android main thread get anR? B: Skipped 3543 frames! Choreographer: Skipped 3543 frames! B: Skipped 3543 frames! The application may be doing too much work on its main thread. Tell me the main thread is no place for you to mess around! emmmm.....
There is no ANR but the interface is really blocked, guess anR is the thread is too busy, not too idle!
Test code:
private void onFetureTaskTest(){
Log.d("FutureTask"."Task Start time:"+ DateUtil.getStringForMillis(Calendar.getInstance().getTimeInMillis(),DateUtil.DATE_YMDHMS)); Callable<String> Callable = new Callable<String>() {@override public String Call () throws Exception { Log.d("FutureTask"."Mission initiated. Wait 60 seconds.");
Thread.sleep(60_000);
Log.d("FutureTask"."Task completed, return result");
return "10"; }}; FutureTask<String> taskFor = new FutureTask<String>(callable){ @Override protected voiddone() {// Define some logic super.done(); }}; Thread thread = new Thread(taskFor); thread.start(); try { Log.d("FutureTask"."Task complete, return result :"+taskFor.get());
Log.d("FutureTask"."Task Completion Time:"+ DateUtil.getStringForMillis(Calendar.getInstance().getTimeInMillis(),DateUtil.DATE_YMDHMS)); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } // What about anr? There is no ANR, but the result is that the page always starts late (subscribing to the startup time based on the execution time of the background FutureTask)}Copy the code
Ok, the problem is solved here. I don’t know what other students think after reading it. Let me know in the comments! Don’t mention it!