2016-05-26 8 views
5

Предоставляет ли Java-модель памяти - прежде чем гарантировать взаимодействие потоков пула? В частности, будет делать записи, сделанные потоком рабочего потока потока, до того, как конец работы элемента из рабочей очереди будет видимым для рабочего потока, следующего за ним после очередного элемента из очереди?. Модель памяти Java происходит раньше, чем обеспечивается взаимодействие пула потоков.

Спецификация (я лично считаю этот FAQ полезным: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization) говорится, что «Вызов, чтобы начать() на поток происходит до каких-либо действий в запущенном потоке.» Или проще говоря, любая память пишет вы делаете перед запуском потока будет выполняться до и видимым для метода 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.valuewrite.run() по гарантированно видны (не спрашивая об упорядочении, это очевидно) к read.run()?

(PS: Я понимаю, что делает valuevolatile действительно обеспечивает эту гарантию)

Update (дополняет ответ): Пакета резюме документации java.util.concurrent суммирует непротиворечивость гарантию памяти, предоставляемую языком и продолженную в рамках : https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

ответ

4

Я думаю, что гарантировано будет видно.ExecutorService расширяет Executor и javadocs для Executor сказать: консистенция

памяти эффекты: Действия в потоке до подачи Runnable объекта в Executorпроизойдет, перед началом его исполнения, может быть, в другом потоке.

По моему чтению это соответствует тому, что происходит в вашем примере. write работоспособным является read подачей работоспособным, так что есть происходит, прежде, чем отношения между событиями до представления в write нити (т.е. set вызова) и событий впоследствии в read нити (т.е. get вызова).

Того факт, что write работоспособного сам передаваемый означает, что существует также происходит, перед тем между созданием Container объекта и вызовом set.

2

Цитирование Javadoc из ExecutorService:

консистенцию памяти эффекты: Действия в потоке до представления задачи Runnable или Callable к ExecutorServiceпроизойдет, перед тем какие-либо действия, предпринятые этой задачи, которая, в свою очередь, произойдет, перед тем результат получен с помощью Future.get().

Но в нем ничего не говорится о двух заданиях, добавленных в очередь, и идет ли обработка задачи 1 - перед обработкой задачи 2, как видно из задачи. Только то, что добавление задачи в очередь происходит до обработки задачи, и выполнение задачи происходит до того, как результат будет получен исходным вызовом.

Update

Существует не происходит, прежде, чем корреляцию между двумя различными, независимо представленными задачами, даже если какой-то образом один известен пробег до завершения, прежде чем начинается другая работа.

Конечно, когда одна задача представляет другую, как это делается в вопросе, любое действие в задаче 1 перед тем она представляет задачу 2, будет произойдет, перед выполнением задачи 2.

Если задача 1 продолжает делать другие вещи после отправки задания 2, то, конечно, ничего не происходит - перед гарантией, потому что задача 2 может выполняться и завершаться до того, как задача 1 получит продолжение ее работы.

+2

Я не следую за вами - ваше заключение противоположно цитированной вами цитате ... В примере op определенно есть отношение hb между 'sharedObject.set (35)' и 'println'. Возможно, вы упустили тот факт, что вторая задача добавляется в очередь * из первой задачи *, а не в основной поток. – assylias

+0

@assylias Вы правы, я пропустил этот факт. Поскольку формулировка моего ответа предполагает, я говорю о двух независимо добавленных задачах, а не о одной задаче, представляющей другую. – Andreas

+0

Спасибо, что заметили несоответствие между моим вопросом и примером. Пример - это то, о чем я хотел знать, но не мог понять вопрос, это было бы: писать действия в 'write', сделанные до отправки' read', видимого в поток 'read'. – Pavel