2013-07-27 60 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; 
    } 
} 

現在,我宣佈yObjvolatile,以確保每一個線程看到同一個對象引用時通過調用setY(Y)方法改變。 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

@zapl中的y你是對的,錯過了。感謝您指出了這一點! – acostalima

回答

1

你的問題的癥結是,private volatile Y yObj;不僅使yObj參考volatile,而不是其內容。

當您稍後做x = yObj.getY();時,您可能正在請求訪問非易失性變量,因此理論上可能導致線程不安全。

製作yObj不可改變可能會有所幫助,但執行這將是困難的。

您的啓動/停止機制看起來不錯,但我會使用AtomicBoolean,放棄同步並使用if(active.compareAndSet(false, true) { ...或類似的。

+0

是的,我知道將yObj聲明爲volatile只會引用volatile而不是其內容。關於將是問題#2的內容。難以執行它嗎?如果Y只提供簡單的getter和setter,那麼通過聲明它的成員變得不穩定嗎?啓動/停止機制可能會拋出異常,所以在這種情況下,該標誌不能改變其狀態。調用compareAndSet(),我相信它在確定前提條件之前確實改變了它的狀態,不是嗎? – acostalima