2013-07-18 1 views
3

필드에 액세스하는 일반적인 방법은 getter와 setter를 동기화하는 것입니다. 이 액세스는 스레드로부터 안전 만드는 안전한 방법 인 반면, 그것도 한 번에 한 스레드 만 foo을 읽을 수있는 알, 이제동기화 된 getter/setter에 대해 여러 번 가져 오기 허용

private int foo = 0; 
public synchronized int get(){return this.foo;} 
public synchronized void set(int bar){ this.foo = bar;} 

: int 형과 간단한 예는 다음과 같다 것이다.

많은 스레드가 foo을 자주 읽으며이 변수를 가끔 업데이트하는 경우 큰 낭비가됩니다. getter는 문제없이 여러 스레드에서 동시에 호출 할 수 있습니다.

이 문제를 해결하는 방법에 대해 알려진 패턴이 있습니까? 아니면 가장 우아한 방법으로이 문제를 해결할 수 있을까요?

답변

5

ReadWriteLock를 살펴 보자 있습니다. 이 인터페이스는 찾고자하는 것입니다. 여러 개의 독자가 있지만 단 하나의 작가 만 사용할 수 있습니다.

예 : volatile가 될

단 하나의 필드와 정말 상호 배제를 요구하는 세터의 복잡한 논리가있는 곳에, 당신으로 간단하게 예를 들어
private int foo = 0; 

private ReadWriteLock rwLock = /* use some implementation of ReadWriteLock here */; 

public int get() { 
    Lock l = rwLock.readLock(); 
    int result = 0; 
    l.lock(); 
    try { 
     result = this.foo; 
    } 
    catch(Exception ex) { 
     // may throw the Exception here 
    } 
    finally { 
     l.unlock(); 
    } 
    return result; 
} 

public void set(int bar){ 
    Lock l = rwLock.writeLock(); 
    l.lock(); 
    try { 
     this.foo = bar; 
    } 
    catch(Exception ex) { 
     // may throw the Exception here 
    } 
    finally { 
     l.unlock(); 
    } 
} 
+0

고맙다. 귀하의 예제에서 동기화 된 메서드가 잠금의 목적을 물리 치지 않거나 동기화 된 작동 방식을 오해 한 적이 있습니까? – Chippen

+0

@Chippen 맞습니다. 수정자를 삭제하는 것을 잊어 버렸습니다. 내 대답을 업데이트 할게. –

3

변수를 설정하고 가져 오는 경우 : volatile을 사용하고 synchronized 메서드를 제거 할 수 있습니다.

덧셈과 같은 정수 연산을 수행하려면 AtomicInteger을 사용해야합니다.

편집 :

필드를 여러 번 읽고 몇 번 업데이트되는 시나리오가있는 경우 다음 IMMUTABLE라는 패턴이있다. 이것이 스레드 안전을 얻는 방법 중 하나입니다.

불변성에 대한 자세한 지식을
class ImmutableClass{ 
     private final int a; 

     public ImmutableClass(int a) { 
      this.a = a; 
     } 

     public int getA(){ 
      return a; 
     } 

     /* 
     * No setter methods making it immutable and Thread safe 
     */ 
    } 

, Java Concurrency In practice 난 당신이 읽을 제안 최고의 자원이다. 더 진보 된 방법을

보기 : Read/Write lock

+0

이는 예입니다 문제를 설명하기 위해, 내용이 복잡 할 수 있으며 원자 작업에 적합하지 않을. read 메소드 자체가 thread safe 인 사실은 여전히 ​​유효합니다. – Chippen

+0

자세한 내용은 [Java 동시성] (http://docs.oracle.com/javase/tutorial/essential/concurrency/)을 참조하십시오. –

+0

답변을 수정했습니다. 나는 당신이 찾고있는 것에 답할 수 있기를 바랍니다 :) –

0

, 당신은 단지 현장을 선언 할 수 있습니다 synchronized 개의 키워드를 삭제하십시오.

더 복잡한 물건 들어, 저렴한 잠금 패턴을 읽기 - 쓰기 사용할 수 있습니다

public class CheapReadWriteLockPattern { 

    // SINGLE-FIELD: 
    private volatile Object obj; 

    public Object read() { 
    return obj; 
    } 

    public synchronized void write(Object obj) { 
    this.obj = obj; 
    } 

    // MULTI-FIELD: 
    private static class Ref { 
    final Object x; 
    final Object y; 
    final Object z; 

    public Ref(Object x, Object y, Object z) { 
     this.x = x; 
     this.y = y; 
     this.z = z; 
    } 
    } 

    private volatile Ref ref = new Ref(null, null, null); 

    public Object readX() { return ref.x; } 
    public Object readY() { return ref.y; } 
    public Object readZ() { return ref.z; } 

    public synchronized void writeX(Object x) { 
    ref = new Ref(x, ref.y, ref.z); 
    } 
    public synchronized void writeY(Object y) { 
    ref = new Ref(ref.x, y, ref.z); 
    } 
    public synchronized void writeZ(Object z) { 
    ref = new Ref(ref.x, ref.y, z); 
    } 
} 
+0

이 저렴한 읽기 - 쓰기 잠금 패턴은 Viktor 및 Narendra의 대답에서 언급 한 라이브러리 읽기/쓰기 잠금보다 장점이 있습니까? – Chippen

+0

@Chippen 예, 독자는 작가를 굶주 리지 않습니다. 또한 휘발성 읽기 및 쓰기는 잠금 작업보다 저렴합니다. 또한 읽기 대/소문자에서 객체 할당을 발생시키지 않습니다. –