2012-10-04 2 views
2

단순한 x++은 원자 연산이 아니지만 사실은 읽기 - 증가 - 쓰기 연산임을 알 수 있습니다. 그것이 동기화되어야하는 이유입니다. 그러나 get()은 어떨까요? 나는 그것도 동기화되어야 읽었지만, 누군가가 왜 나에게 설명 할 수 있을까? happens-before 관계를 도입하여 메모리 일관성 오류를 피하려면? get()이 여러 스레드에서 자주 호출되고 값이 거의 변경되지 않는 경우는 어떻습니까? synchronized get() 그들을 느리게하고 있지 않습니까? 이 시나리오에서 AtomicInteger를 사용하지 않고 다른 방법으로 동기화를 수행 할 수 있습니까? volatile 여기에서 키워드를 사용할 수 있습니까?자바 동기화 된 카운터 - get()은 어떻습니까?

public class Counter { 
    private int value; 

    public synchronized int get() { return value; } 
    public synchronized int increment() { return ++value; } 
    public synchronized int decrement() { return --value; } 
} 

감사합니다.

편집 :

나는 분명히하고 싶습니다. volatile을 사용하여 synchronized을 제거하고 get() 방법에서 해당 키워드를 소개한다는 의미였습니다. 많은 스레드가 값을 읽는 중이고 거의 변경하지 않으면 스레드가 안전 할뿐만 아니라 더 효율적인지 궁금합니다.

답변

10

AtomicInteger를 사용하지 않고이 시나리오에서 동기화를 수행하는 다른 방법이 있습니까?

가능한 경우 먼저 AtomicInteger을 사용해야합니다. 왜 내가 너를 사용하지 않을지 모르겠다.

휘발성 키워드는 여기에서 사용할 수 있습니까?

예 (++ 제외). AtomicInteger은 잠금없이 안전하게 증가합니다. 자신 만의 롤을 만들고 싶다면 블로킹이 필요하거나 내부 회전 메커니즘을 AtomicInteger 복제해야합니다.

하지만 get()은 어떨까요? 나는 그것도 동기화되어야 읽었지만, 누군가가 왜 나에게 설명 할 수 있을까?

AtomicInteger은 기능을 제공하기 위해 volatile int을 래핑합니다. volatile 필드에 액세스하면 get()의 메모리 장벽을 넘습니다. 이 있어야 해당 메모리 장벽을 통과하여 다른 스레드가 값을 업데이트 한 경우 get()을 호출하는 스레드가 업데이트를 확인할 수 있습니다. 그렇지 않으면 매우 오래된 값으로 스레드가 작동 할 수 있습니다.

+0

필자는 AtomicInteger를 사용하지 않는 것과 동일한 동작을 얻으려고했다. P 'volatile '을 사용하여 키워드를 도입하고'get()'메소드에서'synchronized'를 제거했다. 많은 스레드가 값을 읽고 거의 변경하지 않으면 스레드가 안전 할뿐만 아니라 더 효율적인지 궁금합니다. –

+0

예 @JakubKrawczyk, 작동합니다. 'AtomicInteger'보다 더 빨라지려고하십니까? 왜 그 수업을 사용하지 않습니까? 이것이 효율성을위한 것이라면 조기 최적화의 정의를 수행하고 있습니다. – Gray

+0

나는 내 자신의'AtomicInteger'를 구현하려고하지 않고있다. :) 나는 그 문제에서 동기화를 이해하려고 애쓰는 중이었다. 확실한 대답은 "AtomicInteger' 사용"이라고 생각하고 피하고 싶었습니다 : P 작동하지 않았습니다;) 감사합니다! –

1

비 휘발성 값을 반복해서 읽는 경우 JVM은 값을 레지스터에 캐시 할 수 있지만 변경 사항을 볼 수는 없습니다.

이 문제를 피하는 방법은 값을 휘발성으로 만드는 것입니다.

성능이 문제가되는 경우 잠금이없는 AtomicInteger를 사용하십시오.

+0

"레지스터"로 캐시 된 메모리를 의미한다고 가정합니다. @Peter? – Gray

+0

CPU의 레지스터를 의미하지만 캐시 수준에서도 비슷한 문제가 발생합니다. –

+0

"변경 사항이 보이지 않을 수도 있습니다."라는 메시지는 Java 문서가 "synchronized가 happen-before relationship을 설정하는 것"보다 명확하다는 것을 보여줍니다. 면접이 폴링을하는 경우 주문에 신경 쓰지 않아도되지만 결국에는 변경 사항을 확인하는 것이 중요합니다. 그것은 당신의 의견에서 점점 측면 변경을 볼 수 없다는 위험이 나타납니다. – H2ONaCl

0

하지만 get()은 어떨까요? 나는 그것도 동기화해야 읽었지만, 누군가가 왜 나를 설명 할 수 있을까?가정하자

get()가 동기화되지 않은 경우, 그 다음 모든 스레드가 스레드가 set() 동작을 실행하는 동안이를 호출 할 수있을 것이다 ..에

이제 가정하자 경우, 스레드 B가 실행되는 집합() 오퍼레이션 필드 값 a을 5로 설정하십시오. 이제 두 스레드가 값을 읽는다고 가정하십시오. 한 스레드는 설정된 작업이 완료되기 전에 읽은 다음 다른 스레드가 설정된 작업 후에 읽습니다.

따라서 두 스레드 모두 따라서 서로 다른 값을 갖습니다. 따라서 필드의 일관성이 없음 a입니다.

지금

.. 그래서 모든 스레드가 동일한 값을 얻을 것이다 .. 스레드가 값을 설정하는 경우 set() 작업이 완료되지 않는 get() 방법이 syncrhonized 것을 .. 그리고 .. 그리고 어떤 스레드가 get() 조작을 호출 할 수 없습니다 가정
+0

일부 응용 프로그램은 결국 올바른 값을 볼 수있는 한 모든 스레드가 최대한 빨리 같은 값을 볼 필요가 없습니다. @Peter Lawreys의 의견은 그러한 애플리케이션에 대한 위험이 여전히 있음을 시사합니다. – H2ONaCl

0

하지만 get()은 어떨까요? 나는 그것도 동기화되어야 읽었지만, 누군가가 왜 나에게 설명 할 수 있을까? happen-before 관계를 도입하여 메모리 일관성 오류를 방지하려면?

예, 동기화해야합니다. 그렇지 않으면 증가/감소와 마찬가지로 오래된 값을 사용할 수 있습니다.

get()이 여러 스레드에서 자주 호출되어 값이 거의 변경되지 않는 경우는 어떻습니까? 동기화되지 않습니다 get() 그들을 느리게?

비경쟁 잠금은 매우 저렴합니다. 동시 가져 오기의 경우에도 비용이 전반적인 성능에 큰 영향을 미치지 않을 수 있습니다. volatile은 여기에서 작동하지만 AtomicInteger을 사용하지 않아도됩니다.

AtomicInteger를 사용하지 않고이 시나리오에서 동기화를 수행하는 다른 방법이 있습니까? 휘발성 키워드가 여기에서 작동합니까?

네, 그렇습니다.