繁体   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