2013-04-13 3 views
0

항상 '3'이 출력되기 때문에. 동기화가 필요하지 않습니까? 이 간단한 것을 테스트하려고합니다. 왜냐하면 실제의 다중 스레드 문제에 문제가 있습니다. 문제점을 설명하기에는 좋지 않습니다. 이 상황을 보여주는 간단한 버전입니다. 당신이 다른 클래스에 대한 '실행'을 호출 할 때까지 count++ 완료 할만큼 빠른처럼이 스레드는 왜 안전합니까?

class Test { 

public static int count = 0; 

class CountThread extends Thread { 

    public void run() 
    { 
     count++; 
    } 
} 

public void add(){ 
    CountThread a = new CountThread(); 
    CountThread b = new CountThread(); 
    CountThread c = new CountThread(); 

    a.start(); 
    b.start(); 
    c.start(); 

    try { 
     a.join(); 
     b.join(); 
     c.join(); 
    } catch (InterruptedException ex) { 
     ex.printStackTrace(); 
    } 

} 
public static void main(String[] args) { 

    Test test = new Test(); 
    System.out.println("START = " + Test.count); 

    test.add(); 

    System.out.println("END: Account balance = " + Test.count); 
} 
+1

'main' 코드 주위에 루프를 넣으면 그럴 수 없습니다. – Chan

답변

2

나에게 보인다. 그래서 기본적으로 순차적으로 실행됩니다.
그러나 이것이 실제 사례이고 두 개의 다른 스레드가 CountThread을 병렬로 사용하고 있다면 그렇습니다. 동기화 문제가 있습니다.

count ++ 및 after 전에 몇 가지 테스트 출력을 인쇄하려면 b.start()count++을 호출하는지 확인하고 a.start()을 완료해야합니다. c.start()과 동일합니다.

동기화는보다 나은 방법이다 대신 AtomicInteger을 고려하여 가능한 경우 -

incrementAndGet 현재의 값
public final int incrementAndGet()
원자 단위.

+0

IO 또는 PrintStream 동기화 때문에 인쇄하면 스레드 실행 순서가 변경됩니다. 당신이 말하는 것을 증명하는 것은 매우 어려울 것입니다. 비록 그것이 가장 정확합니다. – Gray

+0

synchronized void run()을 사용하는 경우에도 AtomaticInteger()를 사용해야합니까? – user697911

+0

아니요, 더 빠른 결과를 얻을 수 있으므로 AtomicInteger를 사용하는 것이 좋습니다. – danieln

0

출력이 올바르므로 스레드로부터 안전하지 않습니다. 쓰래드를 생성하면 OS의 오버 헤드가 많이 생기고 그 후에는 한 줄의 코드가 단일 타임 슬라이스 내에서 처리 될 것으로 예상됩니다. 어떤 방법 으로든 스레드로부터 안전하지는 않습니다. 잠재적 인 충돌로 인해 실제로는 트리거가 발생하지 않습니다.

0

스레드로부터 안전하지 않습니다.

이 문제를 보여줄 수있는 측정 가능한 기회를 갖기 위해 단락이 된 것 같습니다. run에서 훨씬 더 많은 수 (1000000?)를 계산하여 여러 스레드에서 중복 될 작업을 2 회 증가시킬 수 있습니다. 또한

확인 컴퓨터가 단일 코어 CPU 있지 않은지 확인 ...

4

항상 출력합니다 때문에 '3'. 동기화가 필요하지 않습니까?

스레드 안전하지 않으며 방금 운이 좋았습니다. 1000 번이나 다른 아키텍처를 실행하면 다른 출력 (예 : 3이 아님)이 표시됩니다.

synchronized이 아닌 정적 필드 ++ 대신 AtomicInteger을 사용하는 것이 좋습니다.

public static AtomicInteger count = new AtomicInteger(); 
... 
public void run() { 
    count.incrementAndGet(); 
} 
... 
+0

AtomicInteger를 사용하더라도 여전히 고정적으로 사용해야합니다. – user697911

+1

당신은'CountThread'의 인자로 쓰레드에 카운터를 넘길 수 있습니다. 'static '은 모든 스레드가 동일한 카운터 @ user697911을 참조하는 쉬운 방법입니다. – Gray

+1

-1은 답변에 무엇이 잘못되었는지 설명해 주시겠습니까? – Gray

1

이 코드는 스레드 안전하지 않습니다 : 당신은 하나의 시스템에이 코드를 백만 번 실행할 수 있습니다

public static int count = 0; 

class CountThread extends Thread { 

    public void run() 
    { 
     count++; 
    } 
} 

과 모든 시간을 통과 할 수 있습니다. 스레드로부터 안전하다는 의미는 아닙니다.

count의 값이 여러 프로세서 캐시에 복사되는 시스템을 고려하십시오. 이들 모두는 독립적으로 업데이트되어 무언가가 캐시 중 하나를 주요 RAM으로 다시 복사하게합니다.++은 원자 조작이 아니라고 간주하십시오. count의 읽기 및 쓰기 순서로 인해 데이터가 손실 될 수 있습니다.

이 코드 (위의 자바 5 사용)를 구현하는 올바른 방법 : 클래스 스레드 중 하나가 스레드 간의 메모리 울타리를 강제 할 수 volatile을 만들거나 AtomicInteger를 사용하려면

public static java.util.concurrent.atomic.AtomicInteger count = 
           new java.util.concurrent.atomic.AtomicInteger(); 

class CountThread extends Thread { 

    public void run() 
    { 
     count.incrementAndGet(); 
    } 
} 
0

를, 또는 재 작성 이런 식으로 (내 취향) :

class CountThread extends Thread { 

    private static final Object lock = new Object(); 

    public void run() 
    { 
     synchronized(lock) { 
      count++; 
     } 
    } 
} 
관련 문제