2017-12-28 8 views
0

병렬 lambda를 사용할 때 다음과 같은 문제가 발생했습니다.Lambda in static initialiser threadlocking

배열에 병렬로 반복되는 클래스에서 정적 초기화 블록이 있지만 스택 추적에서 첫 번째 반복이 올바르게 완료되었다는 것을 알았지 만 모든 후속 반복이 차단됩니다. (쓰레드 덤프 상태는 "Waiting for :") 정말 도움이되지 않습니다.

다음은 스레드가 잠그는 코드입니다.

public static class Test { 
    private static final Object[] objects; 

    static { 
     objects = new Object[9]; 
     IntStream.range(0, objects.length).parallel().forEach(i -> objects[i] = null); 
    } 
} 

왜 배열 인덱스를 null로 설정하면 스레드 잠금이 발생하는지에 관해서 머리가 긁히는 경우 다음을 생각해 냈습니다. 정적 블록 내에 임시 배열을 만든 다음 끝에 문제를 해결 한 클래스 배열을 할당했습니다.

public static class Test { 
    private static final Object[] objects; 

    static { 
     Object[] tempObjects = new Object[9]; 
     IntStream.range(0, tempObjects.length).parallel().forEach(i -> tempObjects[i] = null); 
     objects = tempObjects; 
    } 
} 

왜 첫 번째 코드 블록 스레드가 잠겨 있고 두 번째 코드 블록이 그렇지 않은지에 대한 통찰력이있는 사람이 있습니까?

+2

'objects = new Object [9];가 병렬 스트림으로 무엇을하려고하는지 알기를 바랍니다. 또한, 9 번 간단한 작업을 수행하는 병렬 스트림은 완전히 과잉입니다. 병렬은 "마술처럼 더 빠름"을 의미하지 않습니다. –

+2

크기를 정의한 후에 모든 요소가 null이면 null로 초기화하는 이유는 무엇입니까? – prsvr

+0

"첫 번째 반복이 올바르게 완료되고 이후 작업이 차단됩니다"는 의미는 무엇입니까? 이 코드가 호출되는 시간은 단 한 번뿐입니다. – daniu

답변

4

클래스가 static 초기화 될 때 JVM은 클래스 수준의 잠금을 유지합니다. 잠금은 완전히 초기화 될 때까지 다른 스레드가 클래스에 액세스하는 것을 방지합니다.

어쨌든 당신이하려는 일을 할 필요가 없습니다. new Object[9] 배열은 이미 모든 널 (null)로 초기화됩니다. 말할 것도없이, 그것이 작동하더라도, 병렬 처리는 엄청난 오버 헤드를 가지고 있습니다. 오버 헤드는 여러 코어에서이 작업을 분할하여 얻을 수있는 이점보다 훨씬 중요합니다. (9 개 요소가 있으면 아무런 이점이 없습니다.)

+3

더 구체적으로 클래스는 잠겨있어 다른 스레드에서 액세스 할 수 없으므로 실행되는 별도의 스레드 인 람다 코드는 'objects' 정적 필드. 코드의 두 번째 버전은 이니셜 라이저 블록 자체의'objects' 정적 필드에만 액세스하므로 작동합니다. * 결론 : * 정적 초기화 프로그램에서 스레드를 실행하지 마십시오. ** – Andreas