2010-05-19 62 views
7

所以我想有一個存儲一系列股票報價的arraylist。但我保持跟蹤競標價格,詢問每個價格和最後價格。同步讀取到一個java集合

當然在任何時候,出價詢問或給定股票的最後一個可以改變。

我有一個線程更新價格和一個讀取它們。

我想確保在閱讀時沒有其他線程正在更新價格。所以我看着同步收集。但這似乎只阻止閱讀,而另一個線程添加或刪除一個條目到數組列表。

所以現在我到包裝方式:

public class Qte_List { 
private final ArrayList<Qte> the_list; 

public void UpdateBid(String p_sym, double p_bid){ 
    synchronized (the_list){ 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     q.bid=p_bid;} 
} 

public double ReadBid(String p_sym){ 
    synchronized (the_list){ 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     return q.bid;} 
} 

,所以我想這個實現的目標只有一個線程可以做任何事情 - 讀書或更新the_list的內容 - 在同一時間。我正在處理這個權利?

謝謝。

+0

您是否試圖防止寫入同時發生的讀取引用對象?如果是這樣,鎖定集合將無法完成此操作。看到我的答案。 – DJClayworth 2010-05-19 13:48:34

回答

0

據我瞭解,您正在使用地圖來存儲報價;報價數量永遠不會改變,但可以讀取或修改每個報價以反映當前價格。 重要的是要知道,鎖定集合只能防止引用對象在映射中發生的更改:它不以任何方式限制修改這些引用的內容。如果要限制訪問權限,則必須在Quote對象上提供鎖定。

看着你的代碼,但我不相信你有一個重大的同步問題。如果您嘗試在寫作的同時進行閱讀,您可以先取得價格或寫入後的價格。如果你不知道寫作將會發生,那對你無關緊要。你可以在一個較高的水平需要鎖定,這樣

if (getBidPrice(mystock)<10.0) { 
    sell(10000); 
} 

發生作爲一個原子操作,你最終不會在5.0,而不是10.0暢銷。

如果引號的數量真的沒有改變,那麼我建議只允許Qte對象添加到Qte_List的構造函數中。這將使鎖定集合不相關。技術術語使得Qte_List 不可變

+0

謝謝你讓我覺得我需要更清楚地說明要鎖定什麼。將數小時麪條上。 – jeff 2010-05-19 16:52:06

+0

DJ - 另外,我想我現在已經陷入了困惑,試圖去思考這個問題。我正在看你在上面以粗體寫出的內容....鎖定集合並將其標記爲最終的區別是什麼?我認爲把它標記爲最終是防止地圖上的哪些對象發生變化。 – jeff 2010-05-20 01:17:45

+0

@Jeff final只聲明變量爲「不可變」,而不是變量上的對象。所以名單仍然是可變的。如果你想列表是不可變的,請參閱'Collections.unmodifiableList()' – Hardcoded 2010-05-20 07:12:46

1

是的,這會的工作,反正你也不需要自己做,因爲它是在集合框架

Collections.synchronizedList

+1

同步列表將不起作用,因爲他更新該同步塊中列表的條目屬性。 – Hardcoded 2010-05-19 07:44:03

1

這看起來像一個合理的做法已經實施。吹毛求疵的,不過,你可能不應該包括在synchronized塊內return語句:

public double ReadBid(String p_sym){ 
    double bid; 
    synchronized (the_list) { 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     bid = q.bid; 
    } 

    return bid; 
} 

我不知道,如果這只是我的口味還是有一些涉及併發性疑難雜症,但它至少看起來比較乾淨;-)。

2

是的,你是在正確的軌道上,這應該工作。

但爲什麼不使用現有的Hashtable集合,該集合已同步,並已提供鍵值查找?

+2

哈希表(和向量)在JDK 1.2之前,應該避免。相反,考慮Collections.synchronizedMap(Map m)來創建一個線程安全的HashMap。另外,儘管OP沒有明確說明,但我懷疑報價需要按照典型的訂單進行排序。 – Adamski 2010-05-19 08:05:52

1

你的方法應該做的伎倆,但正如你所說,一次只能有一個讀者和作家。這不是很有規模。

有一些方法可以在不失去線程安全性的情況下提高性能。
例如,您可以使用ReadWriteLock。這將允許多個閱讀器一次,但是當有人獲得寫鎖定時,所有其他人都必須等待他完成。

另一種方法是使用適當的集合。看來你可以用一個線程安全的實現Map來交換你的列表。看看ConcurrentMap documentation可能的候選人。

編輯:
假設您需要訂購你的地圖,看看在ConcurrentNavigableMap接口。

1

你有什麼工作,但是每當你想要讀取或更新元素的值時鎖定整個列表是不可縮放的。如果這並不重要,那麼你對所擁有的就沒有問題。如果您想使其更具可擴展性,請考慮以下事項...

你沒有說你是否需要對the_list進行結構修改(添加或刪除元素),但如果你不這樣做,那麼一個重大的改進就是將調用移動到FindBySym()之外同步塊。然後,而不是在the_list上進行同步,您可以在q上同步(Qte對象)。這樣你可以同時更新不同的Qte對象。另外,如果你可以使Qte對象不可變,那麼你根本不需要任何同步。 (更新,只需使用the_list [i] = new Qte(...))。

如果您確實需要對列表進行結構更改,則可以使用ReentrantReadWriteLock來允許併發讀取和獨佔寫入。

我也很好奇你爲什麼要使用ArrayList而不是同步的HashMap。

+0

看起來似乎是一個更有意義的hashmap。我可能默認列出太多而不想。 單個Qte對象上的不可變事物可能會幫助解決部分問題。但我需要多做點工作才能理解它。什麼是使Qte對象不可變的語法,或者我將搜索。另外,不可變意味着「改變」我需要重新分配它的對象? (我正在查看響應中的文本,「要更新,只需使用the_list [i] = new Qte(...)」 – jeff 2010-05-19 16:48:47

+0

不可變意味着「不能改變」。例如,Strings是不可變的,而StringBuffers是你不能改變一個String對象的值(例如,你不能說String s =「a」; s.append(「b」);。 一個不可變的Qte類會有出價,ask價格和最後價格作爲最終成員變量,這3個值將被傳遞給構造函數。成員變量可以是公共的,或者每個成員變量都可以有一個getter(但不包括setter) – Angus 2010-05-21 15:39:36

+0

另外,關於DJClayworth的評論「在寫入之前獲得價格或價格之後的價格「,這隻有在Qte.bid是32位(或更少)值或易失性時才爲真。對於64位非易失性值,可以在寫入過程中讀取並獲取錯誤數據(有關詳細信息,請參閱Java語言規範,第17.7節),因此您需要將Qte.bid更改爲float或int或讓它成爲雙精度並聲明它是不穩定的(如果它不是)。完成之後,您可以安全地讀取和寫入q.bid而無需同步。 (你可以忽略我的不變性建議) – Angus 2010-05-21 15:50:39