2011-04-27 47 views
2

在我的小應用程序中,我有兩個類的線程 - 基本上是作者和讀者。可以將多個閱讀器分配給一個作者。作者通過寫入他們的chunkBuffer變量來與讀者進行交互。現在在Java中共享一個ThreadLocal變量

,我不能完全總結我在這裏的線程安全問題頭:如果我不存儲在一個靜態變量ThreadLocalchunkBuffer,所有讀者將共享一個chunkBuffer,這是不好的。但是如果我確實將chunkBuffer存儲在一個靜態的ThreadLocal中,作爲獨立線程的作者將獲得它自己的chunkBuffer副本並將繼續寫入它,而它寫入的數據都不會到達讀者。你能向我解釋這裏有什麼問題嗎?非常感謝你。

編輯換句話說,有沒有方法來創建一個領域,這將是一個線程子類(如ThreadLocal的)的每一個實例是唯一的,但可以從需求的其他線程訪問?

+0

爲什麼所有讀者都不能共享一個緩衝區? – axtavt 2011-04-27 10:36:03

+0

由於閱讀器可能需要刪除緩衝區中的一些幀,具體取決於閱讀器線程和遠程客戶端之間的連接速度。所以實際上讀者也可以寫入緩衝區,因爲他們可以從中刪除內容。 – dpq 2011-04-27 10:38:26

+0

如果緩衝區寫入正確,我不明白爲什麼寫入不能到達讀取器。其實它不清楚爲什麼你使用ThreadLocal,你應該能夠避免它。 – 2011-04-27 10:39:06

回答

2

沒有。

ThreadLocal用於線程私有數據。在你的情況下,你需要對象溝通所以你需要其他類型的對象。

我認爲使用的最佳結構是同步隊列:java.util.concurrent.LinkedBlockingQueue<E>

隊列允許生產者插入數據和消費者從中消費。如果它是同步的,它允許在不破壞結構的情況下從不同的線程完成。

您可以共享隊列相關的作家/讀者之間:

Writer 1 -> queue 1 -> [readers A/B/C] 

Writer 2 -> queue 2 -> [readers D/E/F] 

每個作者和讀者都會有它的線程。如果沒有項目,每個閱讀器都會嘗試從其隊列中取出一個項目。如果你需要更聰明地管理你的讀者,你可以嘗試更復雜的方法,但我認爲這是一個很好的起點。

+0

所以,基本上,我的失敗在於,不是讓讀者讀取他們傳入的數據自己的線程,我一直試圖從作者推送新的數據到他們的緩衝區(顯然不工作)? – dpq 2011-04-27 10:53:45

+1

我不知道該說什麼。但是作家在自己的線程中執行。讀者同樣的事情。您需要一個共享對象(sync'ed),作者可以「推送」數據,讀者可以「彈出」數據。我談到了隊列的離散項目(),因爲每個作者都有很多讀者。如果有1對1的讀寫器對,他們可以使用其他一些結構(PipedInputStream + PipedOutputStream)。 – helios 2011-04-27 10:58:08

+0

說的。你可以整合兩個想法。 Writer - > pipe - > UnifiedReader - >隊列 - >讀者。呵呵。所以作者可以編寫任意大小的數據。 UnifiedReader總是會讀取8k塊並將其發送到隊列中,以便讀者以並行方式處理它們。但是,如果我不知道你的應用程序,我會走得太遠:) – helios 2011-04-27 11:00:58

0

我不認爲你想使用ThreadLocal變量。你真的需要一個通知機制。

作家執行以下操作:

  1. 寫入新數據的讀者的chunkBuffer
  2. 通知讀者。

有很多方法可以在java併發的東西中做到這一點,但通常最簡單和最安全的方法是使用ArrayBlockingQueue。在你的用例中,聽起來每個Reader都有它自己的ArrayBlockingQueue,它只需要讀取隊列。

這當然取決於你的用例。是否有必要始終處理最新的數據,或者是否需要處理每次寫入chunkBuffer?這些問題對於確定你需要哪種機制是必要的。

注意:支持@helios提到同步隊列,希望我的回答增加了價值。

+0

正如我所說的,我不能直接寫入讀者的chunkBuffer,因爲chunkBuffer必須是線程局部變量。儘管如此,我認爲我應該修復我的應用程序,以便按照@helios提出的方式工作。 – dpq 2011-04-27 11:24:19

+0

爲什麼說chunkBuffer必須是線程局部變量?它可以是讀者對象中的私有變量,並達到相同的目的嗎?線程本地用於不退出或進入線程的事物,例如保證每個線程都有其唯一的Random對象。 – Bringer128 2011-04-28 02:43:56