2014-10-29 80 views
0

考慮我有這段Java代碼Java:使一個代碼塊原子

我想知道是否有一個無鎖定的機制,使突出顯示的代碼片原子。我想避免當有人呼叫fetchSomeThing(),我在BlockXfetchSomeThing()中間從一個新的副本,但是B的舊副本和C.

public class MyClass 
{ 
    private volatile Map a, b, c; 

    public void refresh() 
    { 
     Map a_ = loadA(); 
     Map b_ = loadB(); 
     Map c_ = loadC(); 

     //I want to make the following block atomic 
     // call it Block X 
     { 
     this.a = a_; 
     this.b = b_; 
     this.c = c_; 
     } 
    } 

    public String fetchSomeThing() 
    { 
     // some joint operations on this.a, this.b and this.c 
    } 
} 

我能想到的唯一方法是仰視將其分成兩個類,並將a,b,c包裝在一個對象中。

但它非常麻煩。有沒有更好的辦法?

public class MyShadowClass 
{ 
    private Map a, b, c; 
    public MyShadowClass() 
    { 
     init(); 
    } 

    public void init() 
    { 
     Map a_ = loadA(); 
     Map b_ = loadB(); 
     Map c_ = loadC(); 

     this.a = a_; 
     this.b = b_; 
     this.c = c_; 
    } 

    public String fetchSomeThing() 
    { 
     // some joint operations on this.a, this.b and this.c 
    } 
} 

public class MyClass 
{ 
    private volatile MyShadowClass shadow; 
    public void refresh() 
    { 
     MyShadowClass tempShadow = new MyShadowClass(); 
     shadow = tempShadow; 
    } 

    public String fetchSomeThing() 
    { 
     return shadow.fetchSomeThing(); 
    } 

} 
+0

爲什麼你想要它無鎖?用同步塊來實現將是微不足道的。 – assylias 2014-10-29 15:14:37

+0

@assylias將'synchronized'同時添加到讀取和寫入方法中將會執行此操作,但單獨同步該塊仍然會允許讀取操作在寫入過程中發生。我強烈主張鎖定類,或者使用專用的[讀/寫鎖定](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html )。鎖定類是一個小的修復和簡單的,但讀/寫鎖更強大。 – Floegipoky 2014-10-29 15:17:55

+0

此外,只是想指出,通過不同步'loadX()'操作,你可能會得到一些陳舊的和一些當前的地圖。這可能不是問題,但你至少應該考慮它。 – Floegipoky 2014-10-29 15:41:50

回答

1

只需製作一個持有當前有效狀態的複合對象。然後,您可以利用的AtomicReference來管理當前狀態:

private AtomicReference<Thing> currentThing = new AtomicReference<Thing>(); 

public Thing getThing() { 
     while (true) { 
      Thing result = currentThing.get(); 
      if (result != null) 
       return result; 
      result = buildThing(); 
      if (currentThing.compareAndSet(null, result); 
       return result; 
     } 
} 

private Thing buildThing() { 
     // whatever, only important thing is that this creates 
     // a new and valid instance of Thing 
} 

public void refresh() { 
     Thing freshThing = buildThing(); 
     currentThing.set(freshThing); 
} 

您可以用簡單的聲明「currentThing」正常脫身,但揮發性場,如果你能保證有隻有一個線程編寫場或者當refresh()和initial get併發執行時,您並不特別在意獲取相同的實例。