Java内存模型是否为线程池交互提供了先前发生的保证?特别是,将在从工作队列运行项目结束之前由线程池工作线程进行的写入对于在此之后运行队列中的下一项的工作线程可见吗?
规范(我个人认为此常见问题解答很有用:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization)声明“对线程的start()调用发生在启动线程中的任何操作之前。”或简单地说put,在启动线程之前所做的任何内存写入都将在run()方法执行之前执行,并且启动线程将执行。对于线程池,它是不同的,start()通常在您进行写入之前运行。考虑一个简单的工作流,其中上下文对象被变异并传递给下一个动作:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
private static class Container<T> {
private T value;
public T get() {
return value;
}
public void set(T newValue) {
value = newValue;
}
}
public static void main(String[] args) {
final Container<Integer> sharedObject = new Container<>();
final ExecutorService executor = Executors.newFixedThreadPool(10);
// SKIPPED: pre-warm the executor so all worker threads are start()'ed
final Runnable read = () -> System.out.println("Got " + sharedObject.get());
Runnable write = () -> {
sharedObject.set(35);
executor.execute(read);
};
executor.execute(write);
// SKIPPED: wait until done
}
}
sharedObject.value
对write.run()
的写入保证是read.run()
可见的(不是询问排序,这很明显)吗?
(PS:我知道让value
volatile
提供此保证)
更新(补充答案):
java.util.concurrent
的软件包摘要文档总结了语言提供的内容一致性保证,并由框架扩展:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility
答案 0 :(得分:6)
我认为它保证可见。 ExecutorService
延伸Executor
,而Executor
的{{3}}说:
内存一致性效果:在
Runnable
提交Executor
对象之前,线程中的操作发生在执行开始之前,可能是在另一个线程中。
通过我的阅读,这与你的例子中的内容相符。 write
runnable正在提交read
runnable,因此在write
帖子中提交之前的事件之间存在发生之前的关系(即{{ 1}}调用)以及set
线程中的事件(即read
调用)。
get
runnable本身提交的事实意味着在创建write
对象和调用{{1}之间还存在发生在之前}}
答案 1 :(得分:2)
引用ExecutorService
的javadoc:
内存一致性效果:在向
Runnable
提交Callable
或ExecutorService
任务之前,线程中的操作发生在所采取的任何操作之前该任务,发生 - 之前通过Future.get()
检索结果。
但是,它没有说明添加到队列中的两个任务,以及任务1的处理是否发生 - 在处理任务2之前,从任务中可以看出。只有将任务添加到队列才会在任务处理之前发生,并且任务执行在原始调用者检索结果之前发生。
<强>更新强>
在两个不同的,独立提交的任务之间没有发生 - 之前的相关性,即使以某种方式知道在另一个开始运行之前运行完成。
当然,当一个任务提交另一个任务时,如问题中所做的那样,任务1 在提交任务2之前采取的任何行动,将发生在 - 之前执行任务2.
如果任务1在提交任务2之后继续做其他事情,那么当然没有事先保证,因为任务2可以在任务1继续工作之前运行并完成。