2 回答

TA貢獻(xiàn)1804條經(jīng)驗(yàn) 獲得超7個(gè)贊
首先,讓我們陳述一個(gè)顯而易見的事實(shí) - 最好的解決方案是避免編寫任何此類自定義類。也許像java.util.concurrent.LinkedTransferQueue這樣簡(jiǎn)單的東西也可以工作,并且不那么容易出錯(cuò)。如果 a 不起作用,那么 LMAX 干擾器或類似的東西呢?您是否看過現(xiàn)有的解決方案?LinkedTransferQueue
如果你仍然需要/想要一個(gè)自定義解決方案,那么我有一個(gè)稍微不同的方法的草圖,一個(gè)可以避免復(fù)制的方法:
這個(gè)想法是讓操作圍繞一些原子變量旋轉(zhuǎn),試圖設(shè)置它。如果線程設(shè)法設(shè)置了它,那么它將獲得對(duì)當(dāng)前隊(duì)列的獨(dú)占訪問權(quán)限,這意味著它可以追加到它。追加后,它會(huì)重置原子變量以允許其他線程追加。它基本上是一個(gè)旋轉(zhuǎn)鎖。這樣,線程之間的爭(zhēng)用就會(huì)在追加到隊(duì)列之前發(fā)生,而不是在追加到隊(duì)列之后。put

TA貢獻(xiàn)1868條經(jīng)驗(yàn) 獲得超4個(gè)贊
我需要在每次寫入嘗試時(shí)復(fù)制實(shí)際隊(duì)列
你的想法聽起來像RCU(https://en.wikipedia.org/wiki/Read-copy-update)。Java被垃圾回收通過為您解決解除分配問題使RCU變得更加容易(我認(rèn)為)。
如果我從你的問題的快速瀏覽中正確理解,你的“讀者”實(shí)際上想為自己“聲稱”容器的整個(gè)當(dāng)前內(nèi)容。這也使它們有效地成為編寫者,但是它們不是讀取+復(fù)制,而是可以構(gòu)造一個(gè)空容器,并原子地交換頂級(jí)引用以指向該容器。(因此,聲明舊容器進(jìn)行獨(dú)占訪問。
RCU的一大好處是容器數(shù)據(jù)結(jié)構(gòu)本身不必到處都是原子的。一旦你有對(duì)它的引用,就沒有其他人在修改它。
唯一棘手的部分是當(dāng)作家想要將新內(nèi)容添加到非空容器中時(shí)。然后,您復(fù)制現(xiàn)有容器并修改副本,并嘗試將更新后的副本 CAS(比較交換,即)到共享的頂級(jí)中。compareAndSet()
AtomicReference
一個(gè)作家不能只是無條件地交換,因?yàn)樗赡茏罱K會(huì)得到一個(gè)非空的容器,無處放它。除非編寫器可以堅(jiān)持一批工作并旋轉(zhuǎn)等待讀取器清空隊(duì)列...
我在這里假設(shè)你的作家有一批工作可以同時(shí)排隊(duì);否則RCU對(duì)作家來說可能太貴了。很抱歉,如果我錯(cuò)過了您的問題中的一個(gè)細(xì)節(jié),可以排除這一點(diǎn)。我不經(jīng)常使用Java,所以我只是快速編寫這個(gè),以防萬一它有幫助。
添加回答
舉報(bào)