簡體   English   中英

延遲鎖定時,在持有特定監視器的同時修改對象的易失布爾字段有什么處理?

[英]What is the deal with modifying the volatile boolean field of an object, while holding the specific monitor, when lazy locking?

我實現了一個惰性鎖定列表,該列表支持以下方法:布爾值add(T項),布爾值remove(T項),布爾值contains(T項)。

例如,add方法:

@Override
public boolean add(T item) {
    int key = item.hashCode();

    while(true){
        Node pred = head;
        Node curr = pred.next;

        while(curr.key < key) { pred = curr; curr = curr.next; }

        pred.Lock.lock();
        curr.Lock.lock();

        try{
            if(!pred.marked && !curr.marked && pred.next == curr){
                if(curr.key == key){ return false; }
                else{ Node insertMe = new Node(item); insertMe.next = curr; pred.next = insertMe; return true; }
            }
        } finally{ pred.Lock.unlock(); curr.Lock.unlock(); }
    }
}

如果Node對象具有一個“標記”為易失性布爾字段,則默認情況下設置為false。 節點的鎖是可重入的。 標記為true的節點被視為已經由remove方法刪除。 但是,當特定對象的監視器仍然由特定線程持有時,為什么這甚至相關? 換句話說,線程是否正在隨時獲取對象的鎖,然后看到該節點被標記為已刪除,甚至會發生?

編輯:contains方法顯然根本不會鎖定,但是將標記為已刪除的節點的目的僅僅是為了能夠進行一次contains檢查? 因此,有必要將標記字段聲明為volatile嗎?

包含:

    @Override
public boolean contains(T item) {
    int key = item.hashCode();

    while(true){
        Node curr = head;

        while(curr.key < key) { curr = curr.next; }

        if(curr.key == key && !curr.marked) return true;
        else return false;
    }
}

去掉:

    @Override
public boolean remove(T item) {
    int key = item.hashCode();

    while(true){
        Node pred = head;
        Node curr = pred.next;

        while(curr.key < key) { pred = curr; curr = curr.next; }

        pred.Lock.lock();
        curr.Lock.lock();

        try{
            if(!pred.marked && !curr.marked && pred.next == curr){
                if(curr.key != key) { return false; }
                else{
                    curr.marked = true;
                    pred.next = curr.next;
                    return true;
                }
            }
        } finally{ pred.Lock.unlock(); curr.Lock.unlock(); }
    }
}

在您的情況下, marked是包含方法而不是添加方法必需的。 我的猜測是,添加功能中marked -check的絕對不起作用。

marked字段絕對必須是易變的,因為JIT保留重新排序代碼的權利(如果這樣做會帶來好處)。 唯一的保證是,在更改易失性字段之前,任何對易失性字段進行任何操作之前的代碼都已完全執行(發生在關系之前)。

因此,在上面的代碼中,如果字段不是可變的,則JIT可以決定在調用“包含”的線程中創建marked的線程本地副本,然后再檢查該marked本地版本,但是該版本可能已過時那一點。 在這種情況下,同時運行containsremove可能會導致競爭狀況。

作為附帶說明,應該提到Concurrent包中的Collections解決所有這些問題的方式更加優雅(並且沒有bug),因此,在所有情況下均應優先考慮。 如果復制標准庫中已經存在的類,則通常會更糟地實現它。

暫無
暫無

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

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