2011-02-08 53 views
5

我有一個Java線程相關的問題。Java線程同步,最佳併發實用程序,讀操作

舉一個非常簡單的例子,可以說我有2個線程。

線程A運行StockReader Class實例

線程B運行StockAvgDataCollector Class實例

在線程B,StockAvgDataCollector收集一些市場數據連續地,做了一些重均值/處理和更新的成員變量spAvgData

在線程中Stockreader可以使用getspAvgData()方法訪問StockAvgDataCollector實例及其成員spAvgData。

因此,線程A只執行讀操作,線程B執行讀/寫操作。

問題

  1. 現在,我需要在這種情況下同步或原子功能或鎖定或併發相關的東西?線程A讀取較舊的值並不重要。

  2. 因爲線程A只進行讀取操作而不更新任何內容,只有線程B執行任何寫入操作,是否會出現死鎖情況?

我從以下鏈接粘貼了一段。從該段看來,我確實需要擔心某種鎖定/同步。

http://java.sun.com/developer/technicalArticles/J2SE/concurrency/

讀/寫鎖

當使用一個線程來讀取一個對象的數據,你不一定需要防止另一個線程在同一時間讀取數據。只要線程只讀取數據而不改變數據,沒有理由不能並行讀取數據。 J2SE 5.0 java.util.concurrent.locks包提供了實現這種類型鎖定的類。 ReadWriteLock接口維護一對相關的鎖,一個用於只讀,另一個用於寫入。 readLock()可以由多個讀者線程同時保存,只要沒有寫者。 writeLock()是獨佔的。理論上,很明顯,使用讀寫器鎖來增加併發性會比使用互斥鎖取得更好的性能。但是,這種性能改進只能在多處理器上完全實現,並且數據讀取的頻率與被修改的頻率以及讀取和寫入操作的持續時間相比較。

哪個併發工具在我的例子中會更便宜和適用?

java.util.concurrent.atomic?

java.util.concurrent.locks?

java.util.concurrent.ConcurrentLinkedQueue? - 在這種情況下,StockAvgDataCollector將被添加並且StockReader將被刪除。沒有getspAvgData()方法將被暴露。

感謝 阿米特

+0

對不起,我不知道。剛剛接受了我之前的所有問題。感謝您指出。 – FatherFigure 2011-02-08 23:53:47

回答

3

那麼,當你有很多讀者和至少一個作家時,整個ReadWriteLock事情真的很有意義......所以你保證活潑(如果沒有其他線程正在寫的話,你不會阻止任何讀者線程)。但是,你只有兩個線程。

如果你不介意線程B讀取一箇舊的(但沒有損壞的)spAvgData值,那麼我會去一個AtomicDouble(或AtomicReference,這取決於spAvgData的數據類型)。

因此,代碼看起來像這樣

public class A extends Thread { 
    // spAvgData 
    private final AtomicDouble spAvgData = new AtomicDouble(someDefaultValue); 

    public void run() { 
    while (compute) { 
    // do intensive work 
    // ... 
     // done with work, update spAvgData 
    spAvgData.set(resultOfComputation); 
    } 
    } 

    public double getSpAvgData() { 
    return spAvgData.get(); 
    } 
} 
// -------------- 

public class B { 
    public void someMethod() { 
    A a = new A(); 
    // after A being created, spAvgData contains a valid value (at least the default) 
    a.start(); 
    while(read) { 
     // loll around 
     a.getSpAvgData(); 
    } 
    } 
} 
+0

謝謝你的回答,我認爲他們都很好,值得同等接受。但是,stackoverflow只允許一個答案被接受。 – FatherFigure 2011-02-11 00:21:10

2
  1. 如果你不介意,線程A可以閱讀完整的廢話(包括部分更新的數據)則沒有,你不需要任何同步。不過,我懷疑你應該介意。
  2. 如果您只使用單個互斥鎖或ReentrantReadWriteLock,並且在鎖定時不會暫停或未超時休眠,則不會發生死鎖。如果您確實執行不安全的線程操作,或嘗試推出自己的同步解決方案,那麼您將需要擔心它。

如果您使用阻塞隊列,那麼您還需要一個持續運行的攝入循環StockReaderReadWriteLock在單核處理器上仍然有用 - 無論線程是同時物理運行還是僅通過上下文切換進行交織,問題都是相同的。

如果您至少不使用某種形式的同步(例如volatile),那麼您的讀者可能根本沒有看到任何更改。

+0

謝謝。良好的信息。 – FatherFigure 2011-02-11 00:22:14

3

是,同步是非常重要的,你需要考慮兩個參數:spAvgData變量知名度原子及其更新。爲了保證線程A的線程B中的spAvgData變量的可見性,變量可以被聲明爲volatileAtomicReference。此外,如果涉及更多不變量或更新操作是複合操作(使用同步和鎖定),則還需要警惕更新的操作是原子。如果只有線程B正在更新該變量,則不需要同步,並且可見性應該足以讓線程A讀取變量的最新值。

+0

雖然,Java Spec保證int(和更小)和引用的更新是原子的,所以volatile或int對象引用將起作用,後者提供的對象正在被作者替換。 – 2011-02-09 03:15:53