2011-01-26 6 views
5

브라이언 괴츠 (Brian Goetz 's)는 http://www.ibm.com/developerworks/java/library/j-jtp03048.html에서 포크 - 조인에 관한 멋진 기사를 썼습니다. 여기서는 병합 정렬 알고리즘을 사용하여 배열의 양면에서 정렬을 수행 한 다음 결과를 병합하는 포크 ​​결합 메커니즘을 나열합니다.포크 - 조인에서의 메모리 가시성

알고리즘은 동일한 배열의 두 섹션을 동시에 정렬합니다. 가시성을 유지하기 위해 AtomicIntegerArray 또는 다른 메커니즘이 필요하지 않은 이유는 무엇입니까? 어떤 스레드가 다른 스레드가 수행 한 쓰기를 볼 수 있는지, 아니면 미묘한 버그입니까? 후속 조치로서, Scala의 ForkJoinScheduler도이 보증을합니까?

감사합니다.

+0

배열의 다른 섹션에서 작동하고 있습니다. 합병하기 전까지 논쟁은 없습니다. –

+3

다른 섹션에서 운영되고 있다는 데 동의합니다. 그러나 자바의 메모리 모델의 의미는 변수가 휘발성이 아닌 한 모든 스레드가 모든 쓰기를 볼 수 있다고 보장하지는 않는다. 이 블로그에 따르면 : http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html 휘발성 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; 

당신이 y로하면 y는 사용할 수 읽기 전에 일어난 모든 쓰기 쓰기 모든 시간을 말할 수 있습니다. 예

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

위한 다른 스레드 Y는 스레드 는 Y에 기록이 모든 쓰기 전에 포인트가 될 것이다 상기 한 동기화 포인트를 생성하기 때문이다 (X) = (10)을 읽어을 보증되는 5 = 나타내면 쓰기 후에 표시됩니다.

Fork Join 풀을 사용하면 ForkJoinTask의 조인을 통해 동기화 지점이 만들어집니다. 이제 t2.fork() 및 t1.invoke()가 t2에 가입하면 이전에 발생한 모든 쓰기가 표시됩니다. 이전의 모든 쓰기가 동일한 구조 내에 있으므로 가시성이 안전합니다.

분명하지 않다면 더 자세히 설명 드리겠습니다.

+0

'coInvoke'가'invokeAll'을 호출합니까? –

+0

답변을 보완하기 위해 http://java.sun.com/docs/books/jls/third_edition/html/memory.html#64058도 참조하십시오. –

+0

@Danciel C. Sobral 흥미로운 점은이 예제를 작성할 때 실제로 coInvoke 메서드를 찾고 있다는 것입니다. coInvoke 메서드 자체가 소스 코드에서 제거 된 것 같습니다. 적어도 나는 그것을 더 이상 찾을 수 없다. –

1

병합에는 스레드에서의 결합이 포함되며, 결합은 가시성을 보장합니다.

두 번째 부분은 확실합니다. 병합이 어떻게 구현되는지 모르겠습니다.