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
park
implies 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
/unpark
call.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 frompark
was not due to your condition being fulfilled, you might have consumed anunpark
that was not for you. This in turn implies, that you also must test the condition before callingpark
and not call it when the condition has been fulfilled already. But if you do this, you might skip apark
whenunpark
has been called, so some subsequentpark
call will return immediately.In short, even without “spurious returns”, you always have to test your specific condition before calling
park
and 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
/notify
in asynchronized
block orawait
/signal
when owning aLock
. Both should be used with a pre-test loop for reliable results.