2012-10-04 33 views
2

衆所周知,簡單的x++不是原子操作,實際上是讀增量寫操作。這就是爲什麼它應該同步。但是get()呢?我讀過它應該同步,但有人可以解釋我爲什麼?通過引入happens-before關係來避免內存一致性錯誤? get()經常被多個線程調用,而且值很少改變。是不是synchronized get()放緩他們?在這種情況下是否還有其他方法可以實現同步(不使用AtomicInteger)? volatile關鍵字在這裏工作?Java同步計數器 - get()怎麼辦?

public class Counter { 
    private int value; 

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

謝謝!

編輯:

我想講清楚。通過使用volatile我的意思是介紹該關鍵字和刪除​​在get()方法。我想知道,如果許多線程正在讀取值,而且很少更改它,它是否會使線程安全,但也更有效。

回答

10

有沒有其他的方法來實現同步在這種情況下(不使用AtomicInteger)?

首先,你應該使用AtomicInteger如果你能。我不確定你爲什麼不使用它。

揮發性關鍵字在這裏工作嗎?

是除了不能爲++AtomicInteger提供了一個安全的增量而不鎖定。如果你想推出自己的產品(出於某種瘋狂的原因),那麼你將需要阻止或者你需要複製內部自旋機制。

但get()呢?我讀過它應該同步,但有人可以解釋我爲什麼?

AtomicInteger包裝volatile int以提供其功能。當您訪問volatile字段時,您也會穿越get()上的記憶障礙。您需要需要跨越該內存屏障,以確保如果另一個線程已更新該值,調用get()的線程將看到該更新。否則,一個線程可能會以非常過時的值工作。

+0

我只是試圖達到與AtomicInteger不使用它相同的行爲:P 通過使用'volatile'我的意思是引入該關鍵字並在'get()'方法中刪除'synchronized'。我想知道是否它會使線程安全,但如果許多線程讀取值並且很少更改值,它會更有效。 –

+0

是的@JakubKrawczyk,這將工作。你想比AtomicInteger更快嗎?爲什麼不使用這個類?如果這是爲了提高效率,那麼你正在做過早優化的定義。 – Gray

+0

我不是想實現我自己的'AtomicInteger' :)我只是想了解這個問題的同步。我認爲明顯的答案是「使用AtomicInteger」,我想避免它:P它沒有工作;)謝謝! –

1

如果您反覆讀取非易失性值,JVM可以將該值緩存在寄存器中,您可能看不到任何更改。

避免這種情況的方法是使價值變得不穩定。

但是,如果性能是一個問題,請使用AtomicInteger,它是無鎖的。

+0

我通過「註冊」假設你的意思是緩存的內存,右邊@Peter? – Gray

+0

我的意思是CPU的寄存器,但是在高速緩存級別也會遇到類似的問題。 –

+0

「可能沒有看到任何更改」是一種比Java文檔中的「同步建立一種先前發生的關係」更清晰的hellavalot。有時你不關心訂單,如果獲得方無論如何都在進行投票,但是你最終確實在意最終得到改變。從您的評論中可以看出,獲得方將無法看到變化。 – H2ONaCl

0

但get()呢?我讀過它應該同步,但 可能有人解釋我爲什麼?

假設如果get()不同步,則任何線程將能夠同時線程正在執行一個set()操作來調用它..

現在,如果假設,線程B正在執行組()操作,以將字段a的值設置爲5.現在,假設兩個線程正在讀取值a ..一個線程在設置操作完成之前讀取,並且其他線程在設置操作之後讀取。

因此,兩個線程都具有不同的值。因此,它們具有不一致的字段a

現在假設get()方法syncrhonized。然後,如果一個線程設置的值。然後沒有線程可以調用get()操作,除非set()操作完成。所以每一個線程將得到相同的值..

+0

只要最終看到正確的值,一些應用程序不需要每個線程都儘快查看相同的值。 @Peter Lawreys的評論表明,這類應用仍然存在風險。 – H2ONaCl

0

但get()呢?我讀過它應該同步,但有人可以解釋我爲什麼?通過引入事前關係來避免內存一致性錯誤?

是的,它應該是同步的。如果不是,它可能會使用陳舊的值,就像增加/減少一樣。

get()經常被多個線程調用並且該值很少被更改時情況如何呢?不同步get()減慢它們的速度?

未經驗證的鎖非常便宜。即使對於併發獲取,成本可能也不會影響整體性能。 volatile在這裏工作,但由於性能原因,可能沒有必要使用AtomicInteger

有沒有其他的方法來實現同步在這種情況下(不使用AtomicInteger)?揮發性關鍵字在這裏工作?

是的,我相信會的。