正如Mark和其他人一样,正确回答了get()是run()和get()有效的接口; 这意味着应用程序代码很少直接实例化get()。 为了补充讨论,我提供一个示例,说明在任何Executor之外直接构造和使用FutureTask的情况:
FutureTask task = new FutureTask(()-> {
System.out.println("Pretend that something complicated is computed");
Thread.sleep(1000);
return 42;
});
Thread t1 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
Thread t2 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
Thread t3 = new Thread(()->{
try {
int r = task.get();
System.out.println("Result is " + r);
} catch (InterruptedException | ExecutionException e) {}
});
System.out.println("Several threads are going to wait until computations is ready");
t1.start();
t2.start();
t3.start();
task.run(); // let the main thread to compute the value
在这里,get()用作同步工具,例如run()或类似的屏障原语。 可以使用get()或锁和条件重新实现该功能; get()使其封装精巧,不言自明,优雅且代码更少。
还要注意,必须在任何线程中显式调用FutureTask#run()方法。 周围没有执行者为您执行此操作。 在我的代码中,它最终由主线程执行,但是可以修改get()方法以在调用get()的第一个线程上调用run(),因此第一个到达get()的线程可以是T1,T2或T3中的任何一个 所有剩余线程的计算。
基于此思想-第一个线程请求结果将为其他线程进行计算,而同时进行的尝试将被阻止-基于Memoizer,请参阅“ Java并发实践”中第108页的Memoizer Cache示例。