簡體   English   中英

如何同步對其他類成員的訪問?

[英]How do I synchronize access to a member of a different class?

我試圖弄清楚如何同步對來自不同類的同步列表的讀/寫訪問。

一個小例子:我在一個類ListProvider有一個同步列表,並在另一個類Filter訪問它。 顧名思義,此類基於( isInvalid )驗證檢查isInvalid執行一些過濾。

filter方法首先獲取列表引用,然后收集要刪除的條目到臨時列表中,以免遇到並發修改問題,最后從列表中刪除條目:

public class Filter {

    ListProvider listProvider;

    ...

    public void filter() {
        List<String> listProviderList = listProvider.getList();

        List<String> entriesToRemove = new ArrayList<>();

        // collect
        for (String entry : listProviderList)
            if (isInvalid(entry)) {
                entriesToRemove.add(entry);
            }
        }

        // remove
        for (String entry : entriesToRemove) {
            listProviderList.remove(entry);
        }       
    }
}

我的問題:如何確保在filter讀寫列表的同時沒有其他線程修改列表?

如果它是Filter自己的列表,我將這樣做:

synchronized(myList) {
    // collect
    // remove
}

但在這種情況下,我不確定用作監視器的內容。

但在這種情況下,我不確定用作監視器的內容。

要創建用於特定任務的監視器,使用private final Object是一個很好的模式:

 private final Object listUpdateLock = new Object();
 ...
 synchronized(listUpdateLock) {
    ...
 }

重要的是要確保ListProviderprivate並且對列表的所有訪問都在synchronized塊內完成-即使僅從其中讀取也是如此。

在這種情況下,您要更新列表,可以創建一個臨時列表,然后在完成后將其替換。 我不確定您可以使用ListProvider做到這ListProvider 然后,您可以使列表volatile

在這里,您似乎應該使用 鎖就像是同步的,但是更靈活。 它不需要周圍的塊,並且具有一些擴展功能。 也有一些不同種類的鎖。 ReentrantLock很像同步。

public class ListProvider<E> {
    private final List<E> theList = new ArrayList<E>();
    private final ReentrantLock listLock = new ReentrantLock();

    public final List<E> lockList() {
        listLock.lock();
        return theList;
    }

    public final void unlockList() {
        listLock.unlock();
    }
}

/* somewhere else */ {

    List<E> theList = listProvider.lockList();

    /*
     * perform
     * multiple
     * operations
     *
     */

    listProvider.unlockList();
}

此和同步之間的主要區別是:

  • 實際的鎖定機制是隱藏的。 這對抽象很有好處; 然而,
  • 客戶端必須記住顯式解鎖,而同步監視器退出則在塊定界符處。

有一個稱為ReentrantReadWriteLock的鎖,由於多個線程可以同時讀取,因此您會發現它很有用。 ReadWriteLock解釋了它是如何工作的。

不要遍歷原始列表,而是創建它的副本以查找無效的元素。 完成過濾后,您可以安全地從原始列表中刪除無效的元素:

public class Filter {

    ListProvider listProvider;

    ...

    public void filter() {
        List<String> listProviderCopy = new ArrayList<>(listProvider.getList());

        List<String> entriesToRemove = new ArrayList<>();

        // collect
        for (String entry : listProviderCopy)
            if (isInvalid(entry)) {
                entriesToRemove.add(entry);
            }
        }

        listProvider.getList().removeAll(entriesToRemove);
    }
}

您可能要使用SynchronizedList

List<String> list = new ArrayList<>();

List<String> synch = Collections.synchronizedList(list);

更多

暫無
暫無

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

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