2013-03-05 45 views
7

比方說,我有以下類將被重讀,但只是偶爾寫入。它會在一個多線程的web應用程序中使用,所以它需要是線程安全的:同步寫入訪問易失性字段(便宜的讀寫塊)

public class Foo { 
    private volatile String foo; 
    public String getFoo() { 
     return foo; 
    } 
    public synchronized String setFoo(String in) { 
     this.foo = in; 
    } 
} 

Java併發(http://www.ibm.com/developerworks/java/library/j-jtp06197/index.html)指出,這是爲了保護寫訪問,同時提高讀訪問一個脆弱的方式。什麼是這種模式更強大的替代方案?或者如果foo需要在讀取繁重的環境中可變,那麼還有其他選擇嗎?謝謝。

回答

14

揮發性提供到現場快速線程安全無鎖訪問,而同步

private volatile String foo; 

public String getFoo() { 
    return foo; 
} 
public void setFoo(String in) { 
    this.foo = in; 
} 

揮發性解決了3個問題1)存儲器能見度2)原子寫入雙和長字段3)禁止指令重新排序。但是,如果您需要將某個字段作爲一個原子事務進行多次操作(如增量),這還不夠。該代碼被破

private volatile int id; 

public void incrementId() { 
    id++; 
} 

因爲如果2個線程simulataneously讀和增加它並保存結果則第一增量的結果將與第二增量的結果覆蓋。爲了防止這種情況發生,我們需要使用同步

private int id; 

public synchronized int nextId() { 
     return ++id; 
} 

或java.util.concurrent.atomic包

private AtomicInteger id = new AtomicInteger(); 

public void incrementId() { 
    return id.incrementAndGet(); 
} 
+1

將變量標記爲易失性不會使其線程安全。如果所有的OP都在讀/寫,那麼實際上它是線程安全的(如果多個線程正在遞增備份變量,則這不會成立)。 – 2013-03-05 01:48:06

+0

那麼在volatile和synchronized都適合的情況下會出現什麼情況? – oberger 2013-03-05 04:26:43

+2

我相信沒有這種情況。如果您將訪問權限同步到一個字段,那麼volatile是多餘的。 – 2013-03-05 04:32:19

2

如果你正在做的是設置FOO,那麼你並不需要同步方法。使參考變得足夠。

+0

如果我在setter方法中做得更多?如複製操作或子字符串操作。我會同步還是使用兩者? – oberger 2013-03-05 04:28:34

+0

在setter中需要原子性相對於字符串值的任何其他動作都需要使用同步,這會使volatile修飾符無用 – 2013-03-05 06:27:22

+1

@OwenBerger - 如果您需要在setter中做更多的工作,那麼是的,您會需要同步。然而,volatile在這種情況下仍然有用,因爲它允許你不同步getter(假設你不在乎getter的調用者是否獲得舊值而另一個調用者在setter中)。 – jtahlborn 2013-03-05 13:06:26

2

link你說有這個代碼爲「罕見的更新」用法:

@ThreadSafe 
public class CheesyCounter { 
    // Employs the cheap read-write lock trick 
    // All mutative operations MUST be done with the 'this' lock held 
    @GuardedBy("this") private volatile int value; 

    public int getValue() { return value; } 

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

increment方法只使用同步,因爲它不僅僅是設置的value值作爲規定做更多說明,如果你正在做的是this.foo = in;那就是原子。 在文本中,「這種模式的脆弱性」意味着當您將易失性和其他同步方法混合使用以做更多的事情時,事情可能會非常快速地變得混亂。 查看包java.util.concurrent.locks的接口條件和類ReentrantLock。我認爲,並且使用同步是作者通過「更強大的選擇」所表達的意思。你也應該看到Object.waitObject.notify and Object.notifyAll如果你還不知道的話。