i found FutureTask get() method may distable LockSupport.park in oracle jdk8
my code is :
ExecutorService service = Executors.newFixedThreadPool(1, (r) -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
});
Future<String> submit = service.submit(() -> {
TimeUnit.SECONDS.sleep(5);
System.out.println("exec future task..");
return "a";
});
System.out.println(submit.get());
LockSupport.park(new Object());
System.out.println("error,unPark");
}
i thoughtSystem.out.println("error,unPark");would not execute;but it did
exec future task..
a
error,unPark
for simulating thread schedule,I break point on FutureTask line 418
queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
step over fastly before print exec future task..
after print exec future task.. for a while , continue to execute ..
then skip LockSupport.park(new Object()); and print error,unPark
i think
1.FutureTask add getting thread(main) in waiters;
2.execution thread(the thread pool) finish the task,and unpark all waiters;
3.getting thread(main) read state and found task hash finished, then return result and skip executing FutureTask locksupport.park()
4.because unpark method was executed in futuretask,then can skip LockSupport.park(new Object());and print error,unPark
is it a bug?
The documentation does says:
The third bullet alone would be enough to tell you that you can’t assume that returning from
parkimplies that the condition you’re waiting for has been fulfilled.Generally, this tool is meant for code that can not assume atomicity for the operation that checks/induces the condition and the
park/unparkcall.As the documentation concludes you have to re-check the condition after returning from
park. Special emphasis on “re-”; since this implies that you might find out that the return fromparkwas not due to your condition being fulfilled, you might have consumed anunparkthat was not for you. This in turn implies, that you also must test the condition before callingparkand not call it when the condition has been fulfilled already. But if you do this, you might skip aparkwhenunparkhas been called, so some subsequentparkcall will return immediately.In short, even without “spurious returns”, you always have to test your specific condition before calling
parkand re-check the condition after returning frompark, in a loop if you want to wait for the condition.Note that most of it also applies to using
wait/notifyin asynchronizedblock orawait/signalwhen owning aLock. Both should be used with a pre-test loop for reliable results.