我发现FutureTask get()方法可以在oracle jdk8中发布LockSupport.park
我的代码是:
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");
}我原以为System.out.println("error,unPark");不会执行,但它执行了
exec future task..
a
error,unPark为了模拟线程调度,我在FutureTask代码行418上断点。
queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
在打印exec future task..前快速超越
打印exec future task..一段时间后,继续执行..。
然后跳过LockSupport.park(new Object());并打印error,unPark
我认为
1.在服务生中添加获取线程(Main);
2.执行线程(线程池)完成任务,解除所有等待者;
3.获取线程(主)读取状态并找到任务哈希,然后返回结果并跳过执行FutureTask locksupport.park()
4.由于unpark方法是在futuretask中执行的,因此可以跳过LockSupport.park(new Object());并打印error,unPark。
是虫子吗?
发布于 2021-04-16 08:04:11
文献资料确实说:
为线程调度目的禁用当前线程,除非许可可用。 如果许可可用,则使用它并立即返回调用;否则,出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到发生以下三种情况之一:
此方法不报告其中哪一个导致方法返回。调用者首先应该重新检查导致线程停车的条件。调用方还可以确定,例如,返回时线程的中断状态。
光是第三颗子弹就足以告诉您,您不能假设从park返回意味着您正在等待的条件已经满足。
通常,此工具用于不能为检查/诱导条件的操作和park/unpark调用假定原子性的代码。
如文档所示,您必须在从park返回后重新检查条件。特别强调“re-”;因为这意味着您可能会发现park的返回并不是因为您的条件得到满足,所以您可能已经消耗了一个不适合您的unpark。这反过来意味着,您还必须在调用park之前测试条件,而不是在条件已经满足时调用它。但是,如果这样做,则可能在调用park时跳过unpark,因此一些后续的park调用将立即返回。
简而言之,即使没有“虚假返回”,您也必须在调用park之前测试您的特定条件,并在从park返回后在一个循环中重新检查条件,如果您想等待该条件的话。
请注意,它的大部分也适用于在一个wait块中使用synchronized /notify,或者在拥有一个Lock时使用await/signal。这两种方法都应该与预测试循环一起使用,以获得可靠的结果。
https://stackoverflow.com/questions/67118821
复制相似问题