2010-07-22 6 views
2

나는 동기화없이 서로 다른 스레드에서 동일한 객체에 동시에 액세스한다는 것은 일반적으로 나쁜 것임을 알고 있습니다. 하지만이 경우는 어떻게됩니까?자바 다중 스레드 원시 변수 액세스

여러 개의 스레드가 실행 중입니다 (ThreadA & ThreadB 두 개를 고려하십시오). 또한 Thread가 무언가를하는 횟수를 세는 정적 클래스를 가지고 있습니다.

public class Counter { 
    static private int counter=0; 
    static public void incCounter() { 
    counter++; 
    } 
} 

ThreadA와 ThreadB가 모두 Counter.incCounter()를 호출하면 어떻게됩니까?

+0

비참한 아무것도하지만 카운터가 정확 합하지 않습니다 : 잘못된 언어를 사용 할 수없는 경우

말했다되고있다. – irreputable

+0

@irreputable : "재앙"이라고 생각하는 것에 따라 다릅니다. 중요한 것이 카운터에 의존하면 실패합니다. –

+0

다른 스레드의 동일한 객체에 액세스하는 것이 나쁜 이유는 무엇입니까? 필요한 경우 필요합니다. –

답변

11

안전하지 않습니다.

각 스레드는 counter을 읽고 그 중 하나를 추가하여 결과를 다시 쓰려고 시도합니다. 이러한 읽기 및 쓰기의 순서가 보장되지 않거나 결과가 각 스레드에 표시되는 경우에도 보장되지 않습니다.

특히 하나의 실패 사례는 각 스레드가 값 0을 읽고 1로 증가시키고 값 1을 다시 쓰는 것입니다. 이렇게하면 두 스레드가 증분을 시도한 후에도 카운터에 값 1이 제공됩니다.

대신 AtomicInteger.incrementAndGet()을 사용하는 것이 좋습니다.

+0

허, 그것이 존재한다는 것을 결코 알지 못했습니다. 매일 학교 수업이 있네. 감사. – Kevin

0

정적 객체인지 인스턴스인지는 중요하지 않습니다. 여러 스레드에서 변경하는 경우 문제가 발생합니다.

1

이 값은 1 또는 2입니다.이 컨텍스트에서는 정적 변수와 비 정적 변수간에 차이가 없습니다.

0

충돌을 피하기 위해 synchronized 키워드를 사용하십시오.

public class Counter { 
    static private int counter=0; 
    public static synchronized void incCounter() { 
     counter++; 
    } 
} 

이 키워드는 하나의 스레드 만 incCounter()를 호출 할 수 있습니다.

+2

이것은 작동하지만 'AtomicInteger'와 비교할 때 비효율적입니다. – finnw

0

Dave는 정확하지만 빠른 방법은 해당 메서드 설명에 "synchronized"키워드를 추가하는 것입니다. 여러 스레드가 해당 메서드를 호출하면 메서드 내부에서 (인 타이틀을 얻은) 증분 및 존재할 때까지 메서드 경계에서 차단되고 두 번째 호출자가 입력됩니다.

이것은 싱글 톤 클래스에서 좋은 "getInstance()"메소드를 설계하는 것과 비슷합니다. 당신은 일반적으로 2 + 스레드가 메서드를 입력하는 경우가 없기 때문에 ALL이 "instance"가 null임을 확인한 다음 ALL이 새 인스턴스를 만들고이를 로컬 멤버에 할당 한 다음 반환 할 수 있도록 동기화되도록합니다. .

스레드가이 경우 "동일한"인스턴스에 대한 다른 참조로 끝날 수 있습니다. 따라서 코드 블록을 동기화하고, 첫 번째 스레드가 null 인 경우에만 인스턴스를 작성하게하고, 그렇지 않으면 항상 동일한 호출자를 모든 호출자에게 리턴하게합니다.

if (instance == null) 확인 및 반품이 저렴합니다. 마이크로 세컨드의 순서에 따라 나는 미래의 getInstance (또는 당신의 예제 incCounter) 호출을 믿는다. 그래서 당신이 필요하다면 synchronized 키워드에서 벗어날 필요가 없다. 그것이 바로 그 때문입니다. 당신이 여분의 마이크로 ... 그럼 당신이

관련 문제