簡體   English   中英

無障礙方法中的飢餓

[英]Starvation in non-blocking approaches

我已經閱讀了一段時間的非阻塞方法。 這是所謂的無鎖計數器的一段代碼。

public class CasCounter {
private SimulatedCAS value;

public int getValue() {
    return value.get();
}

public int increment() {
    int v;
    do {
        v = value.get();
    }
    while (v != value.compareAndSwap(v, v + 1));
    return v + 1;
}

}

我只是想知道這個循環:

do {
    v = value.get();
}
while (v != value.compareAndSwap(v, v + 1));

人們說:

因此,它會一次又一次嘗試,直到所有其他試圖更改值的線程都這樣做為止。 這是無鎖的,因為沒有使用鎖,但不是無鎖的,因為它可能必須重試一次(這種情況很少)(一次以上)(非常罕見)。

我的問題是:

他們怎么能這樣確定? 對我而言,除非JVM有一些特殊的機制可以解決這個問題,否則我看不出為什么這個循環不會無限長。

編輯 :我想我現在有一個滿意的答案。 令我感到困惑的是“ v!= compareAndSwap”。 在實際代碼中,如果該值等於比較的表達式,則CAS返回true。 因此,即使第一個線程在get和CAS之間中斷,第二個線程也會成功進行交換並退出該方法,因此第一個線程將能夠執行CAS。

當然,如果兩個線程無數次調用此方法,則其中一個根本不會獲得運行CAS的機會,尤其是在優先級較低的情況下,但這是操作的風險之一。不公平的鎖定(但是概率很低)。 就像我說的那樣,隊列機制將能夠解決此問題。

很抱歉最初的錯誤假設。

循環可以是無限的(因為它可以為您的線程產生飢餓),但是這種情況發生的可能性很小。 為了使您挨餓,您需要一些其他線程來成功更改您要在讀取和存儲之間更新的值,並使其重復發生。

可能會編寫代碼來觸發飢餓,但是對於實際程序而言,這不太可能發生。

當您認為自己不會經常發生寫沖突時,通常使用比較和交換。 假設您更新時有50%的“未命中”機會,那么有25%的機會您會在兩個循環中錯過,而少於0.1%的機會是沒有更新會在10個循環中成功。 對於現實世界的示例,50%的未命中率非常高(基本上沒有做任何事情都只能進行更新),並且隨着未命中率的降低,可以說1%,那么兩次嘗試不成功的風險僅為0.01%,而3次失敗嘗試0.0001%。

用法類似於以下問題

將變量a設置為0,並讓兩個線程同時以a = a + 1一百萬次對其進行更新。 最后,a可能有1000000(由於覆蓋而丟失所有其他更新)和2000000(沒有覆蓋任何更新)之間的任何答案。

您越接近2000000,CAS使用的可能性就越大,因為這意味着CAS通常會看到期望值並能夠使用新值進行設置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM