简体   繁体   English

Java内存模型发生在线程池交互的保证之前

[英]Java Memory Model happens-before guarantees for Thread Pool interactions

Does Java Memory Model provide happens-before guarantee for Thread Pool interactions? Java内存模型是否为Thread Pool交互提供了先前发生的保证? In particular, will writes made by a thread pool worker thread before the end of running an item from a work queue be visible to a worker thread running the next item from the queue after that? 特别是,在工作队列中运行项目结束之前由线程池工作线程进行的写入是否会在之后从队列中运行下一个项目的工作线程可见?

The specification (I personally find this FAQ useful: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization ) states that " A call to start() on a thread happens before any actions in the started thread. " or simply put, any memory writes you make before starting a thread will be executed before and visible to the run() method the started thread is going to execute. 规范(我个人觉得这个常见问题解答很有用: http//www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization )声明“对a的调用start()线程在启动线程中的任何操作之前发生。 “或者简单地说,在启动线程之前所做的任何内存写入都将在执行之前执行并且对run()方法可见。 It is different for a thread pool, the start() would normally run before you make a write. 对于线程池,它是不同的,start()通常在您进行写入之前运行。 Consider a simple workflow where a context object is mutated and passed to the next action: 考虑一个简单的工作流,其中上下文对象被变异并传递给下一个动作:

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
    }
}

Is the write to sharedObject.value by write.run() guaranteed to be visible (not asking about ordering, this is obvious) to read.run() ? write.run()sharedObject.value的写入是否保证是可见的(不要询问排序,这很明显) read.run()

(PS: I understand that making value volatile does provide this guarantee) (PS:据我所知,使value volatile确实提供了这种保证)

Update (complements the answer): Package summary documentation for java.util.concurrent summarizes memory consistency guarantees provided by the language and extended by the framework: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility 更新(补充答案): java.util.concurrent软件包摘要文档总结了语言提供并由框架扩展的内存一致性保证: https//docs.oracle.com/javase/7/docs/api/java/ UTIL /并发/包summary.html#MemoryVisibility

I think that it is guaranteed to be visible. 我认为它保证是可见的。 ExecutorService extends Executor , and the javadocs for Executor say: ExecutorService延伸Executor ,和javadoc文档Executor说:

Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread. 内存一致性效果:在将Runnable对象提交给Executor之前,线程中的操作发生在执行开始之前 ,可能在另一个线程中。

By my reading, that matches what is going on in your example. 通过我的阅读,这与你的例子中的内容相符。 The write runnable is submitting the read runnable, so there is a happens-before relationship between events before the submission in the write thread (ie the set call) and the events afterwards in the read thread (ie the get call). write runnable正在提交read runnable,因此在write线程(即set调用)中提交之前的事件与之后在read线程中的事件(即get调用)之间存在一个before-before关系。

The fact that the write runnable is itself submitted means that there is also a happens-before between the creation of the Container object and the call to set . write runnable本身提交的事实意味着在创建Container对象和set的调用之间也存在一个发生的事件

Quoting javadoc of ExecutorService : 引用ExecutorService javadoc:

Memory consistency effects: Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task, which in turn happen-before the result is retrieved via Future.get() . 内存一致性效果:在向ExecutorService提交RunnableCallable任务之前的线程中的操作发生在该任务ExecutorService 任何操作之前 ,而该操作又发生在通过Future.get()检索结果之前

But, it says nothing about two tasks added to the queue, and whether processing of task 1 happens-before processing of task 2, as seen from the task. 但是,它没有说明添加到队列中的两个任务,以及任务1的处理是否发生 - 在处理任务2之前,从任务中可以看出。 Only that adding the task to the queue happens before the task processing it, and the task execution happens before the result is retrieved by the original invoker. 只有将任务添加到队列才会在任务处理之前发生,并且任务执行在原始调用者检索结果之前发生。

Update 更新

There is no happens-before correlation between two different, independently submitted tasks, even if somehow one is known the run to completion before the other begins running. 在两个不同的,独立提交的任务之间没有发生 - 之前的相关性,即使以某种方式知道在另一个开始运行之前运行完成。

Of course, when one task submits another, as is done in the question, any action taken in task 1 before it submits task 2, will happen-before the execution of task 2. 当然,当一个任务提交,好像是在问题后,在任务1所采取的任何行动将其提交任务2 之前发生-前任务2的执行。

If task 1 continues to do other stuff after submitting task 2, there is of course no happen-before guarantee, because task 2 may run and complete before task 1 gets to continue it's work. 如果任务1在提交任务2之后继续做其他事情,那么当然没有事先保证,因为任务2可以在任务1继续它的工作之前运行并完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM