2013-07-27 4 views
3

동기화 된 휘발성 키워드/idoms에 대한 기사를 많이 읽었으며 제대로 작동하는지, 언제 사용해야하는지 잘 이해하고 있다고 생각합니다. 그러나, 나는 아직도 내가하려고하는 것에 대해 약간의 의구심을 가지고있다. 다음을 고려하십시오.동시 액세스 : 변동성 및 동기화

public class X { 
    private volatile int x; 

    public X(int x) { 
    this.x = x; 
    } 

    public void setX(int x) { 
    this.x = x; 
    } 

    public int getX() { 
    return x; 
    } 
} 

위의 내용은 거의 직선적이고 스레드로부터 안전합니다. 이제 다음과 같이 변경과 같은 클래스 X을 고려

public class X { 
    private volatile int x; 
    private volatile Y yObj; 
    private volatile boolean active; 

    public X(Y yObj) { 
    this.yObj = yObj; 
    active = false; 
    x = yObj.getY(); 
    } 

    public void setX(int x) { 
    if (active) throw new IllegalStateException() 
    if (!yObj.isValid(x)) throw new IllegalArgumentException(); 
    this.x = x; 
    } 

    public void setY(Y yObj) { 
    if (active) throw new IllegalStateException(); 
    this.yObj = yObj; 
    x = yObj.getY(); 
    } 

    public int getX() { 
    return x; 
    } 

    public Y getY() { 
    return yObj; 
    } 

    public synchronized void start() { 
    if (active) throw new IllegalStateException(); 
    /* 
     * code that performs some initializations and condition checking runs here 
     * does not depend on x and yObj 
     * might throw an exception 
     */ 
     active = true; 
    } 

    public synchronized void stop() { 
     if (!active) throw new IllegalStateException(); 
     /* some code in the same conditions of the comments in the start() 
     * method runs here 
     */ 
     active = false; 
    } 

    public boolean isActive() { 
    return active; 
    } 
} 

지금, 나는 setY(Y) 메서드를 호출하여 변경 될 때마다 단일 스레드가 같은 개체 참조를 볼 수 있도록 volatileyObj을 선언했다. Y 클래스의 아이디어는 X 개체의 setter를 호출 할 때 X 클래스에 참조 값 집합 (이 예제에서는 하나)을 제공하는 것입니다. 질문은 다음과 같습니다

  1. x 여전히 volatile로 선언하고 모든 스레드에 대한 공통의 시인성을 확보 또는 추가 동기화가 필요 할 수 있습니까?
  2. 아이디어는 클래스 Y의 모든 객체를 변경 불가능하게 만드는 것입니다. 그래서, 나는 모든 필드가 불변 이어야만한다고 가정합니다. Y 사용자를 구현 가능하게 만드는 가장 좋은 방법은 무엇이지만 동시에 스레드로부터 안전합니까? 스레드 안전 메커니즘을 구현 한 추상 클래스는 확장 가능합니까? 현재 Y은 스레드 세이프가 아닌 getter 메소드를 구현할 수있는 인터페이스입니다.
  3. 동시 액세스의 관점에서 시작/중지 메커니즘이 올바르게 구현 되었습니까?
+1

예를 들어,'setY'는 2 개의 비동기 조작을 사용합니다. 'getX()'는 새로운'x'를 보지 않고 새로운'yObj'를 보게됩니다. 잠재적으로 스레드 세이프가 아닙니다. 또한'setX'와'setY'는 안전하지 않습니다. setX의 x로 끝날 수 있지만 setY – zapl

+0

의 y는 맞습니다. 그 점을 지적 해 주셔서 감사합니다! – acostalima

답변

1

문제의 핵심은 private volatile Y yObj;yObj 참조 volatile이 아닌 내용을 만드는 것입니다.

나중에 x = yObj.getY();을 수행 할 때 이론적으로 스레드 안전하지 않은 비 휘발성 변수에 대한 액세스를 요청할 수 있습니다.

yObj을 변경할 수 없게하는 것이 도움이되지만 시행하기가 어려울 수 있습니다.

시작/정지 메커니즘이 잘 보이지만 AtomicBoolean을 사용하고 동기화를 중단하고 if(active.compareAndSet(false, true) { ... 또는 그와 비슷한 것을 사용하십시오.

+0

예, 휘발성으로 yObj를 선언하면 해당 내용이 아닌 참조가 휘발성이됩니다. 질문 # 2가 될 내용에 관해서. 그것을 강요하는 것이 어려울까요? Y가 단순한 getter와 setter만을 제공한다면 멤버를 휘발성이라고 선언함으로써 곧바로 앞으로 나아갈 수는 없을 것입니까? 시작/중지 메카니즘은 던져 질 수 있고 예외가 될 수 있으므로,이 경우 플래그는 그 상태를 변경하면 안된다. compareAndSet()을 호출하면 전제 조건을 평가하기 전에 상태를 바꿀 수 있다고 생각합니다. – acostalima