2011-01-26 3 views
5

Брайан Гетц написал хорошую статью о fork-join на http://www.ibm.com/developerworks/java/library/j-jtp03048.html. В нем он перечисляет алгоритм сортировки слияния, используя механизм fork-join, в котором он выполняет сортировку с двух сторон массива параллельно, а затем объединяет результат.Наблюдение за памятью в вилке-присоединении

Алгоритм сортируется по двум различным разделам одного и того же массива одновременно. Почему для поддержания видимости не требуется AtomicIntegerArray или какой-либо другой механизм? Какая гарантия, что один поток увидит записи, сделанные другим, или это тонкая ошибка? В качестве продолжения, делает ли Scala ForkJoinScheduler эту гарантию?

Спасибо!

+0

Они работают на разных участках массива. Там нет споров, пока не произойдет слияние. –

+3

Я согласен, что они работают на разных разделах. Но семантика модели памяти Java более или менее говорит о том, что не все потоки гарантированно будут видеть все записи (если переменная нестабильна). Согласно этому блогу: http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html даже использование volatile int [] недостаточно, чтобы гарантировать, что другие потоки видят вашу запись в массив –

ответ

5

Для соединения (из ForkJoin) требуется точка синхронизации, то есть самая важная часть информации. Точка синхронизации гарантирует, что все записанные записи будут видны после указанной точки.

Если вы посмотрите на код, вы увидите, где находится точка синхронизации. Это только один вызов метода invokeAll

public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) { 
    t2.fork(); 
    t1.invoke(); 
    t2.join(); 
} 

Здесь t2 вилы в другой процесс, t1 выполняет свою задачу, и вызывающий поток будет ждать t2.join(). При передаче t2. Затем все записи в t1 и t2 будут видны.

Редактировать: Это изменение только для того, чтобы дать более подробное объяснение того, что я имел в виду под точкой синхронизации.

Допустим, что у вас есть две переменные

int x; 
volatile int y; 

Каждый раз, когда вы пишете у всех пишет, что произошло, прежде чем читать у будет доступен. Например

public void doWork(){ 
    x = 10; 
    y = 5; 
} 

Если другой поток читает у = 5, что нить гарантируется для чтения х = 10. Это потому, что записи в у создает точку синхронизации, в которой все операции записи перед указанной точкой будет видимый после записи.

С помощью вилки Join pool объединение ForkJoinTask создаст точку синхронизации. Теперь, если t2.fork() и t1.invoke(), объединение t2 будет гарантировать, что все записи, которые ранее произошли, будут видны. Поскольку все предыдущие записи находятся в одной структуре, это будет безопасно для видимости.

Я был бы рад объяснить, если это не так ясно.

+0

Вызывается 'invokeAll' под названием' coInvoke'? –

+0

И, чтобы дополнить ответ, см. Также http://java.sun.com/docs/books/jls/third_edition/html/memory.html#64058. –

+0

@ Danciel C. Sobral, которого вы интересуете, когда я писал этот пример, я действительно искал метод coInvoke. Похоже, что сам метод coInvoke был очищен от исходного кода. Это, по крайней мере, я не могу найти. –

1

Просто догадка: объединение включает присоединение к потоку, и соединение гарантирует видимость.

Вторая часть уверена; Я не знаю, как реализовано объединение.

Смежные вопросы