JAVA:用于访问Java中列表的并发控制 [英] JAVA: Concurrency control for access to list in java

查看:66
本文介绍了JAVA:用于访问Java中列表的并发控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个多线程应用程序,该应用程序的中心列表仅由主线程更新(写入).然后,我还有其他几个线程需要定期检索当前状态的列表.有什么方法可以让我做到这一点?

I have a multi-threaded application that has a centrlaised list that is updated (written to) only by the main thread. I then have several other threads that need to periodically retrieve the list in its current state. Is there a method that can allow me to do this?

推荐答案

这取决于您如何限制并发性.最简单的方法可能是使用 CopyOnWriteArrayList .当您从中获取迭代器时,该迭代器将反映列表在创建迭代器时的外观-迭代器将看不到后续修改.好处是它可以应付很多争用,缺点是添加新项相当昂贵.

That depends on how you want to restrict the concurrency. The easiest way is probably using CopyOnWriteArrayList. When you grab an iterator from it, that iterator will mirror how the list looked at the point in time when the iterator was created - subsequent modifications will not be visible to the iterator. The upside is that it can cope with quite a lot of contention, the drawback is that adding new items is rather expensive.

另一种方法是锁定,最简单的方法可能是用

The other way of doing is locking, the simplest way is probably wrapping the list with Collections.synchronizedList and synchronizing on the list when iterating.

第三种方法是使用某种 BlockingQueue 并将新元素提供给工作人员.

A third way is using some kind of BlockingQueue and feed the new elements to the workers.

编辑:由于OP声明仅需要快照,因此CopyOnWriteArrayList可能是最好的即用型替代方案.另一种方法(添加成本较低,但阅读成本较高)是仅在需要遍历时创建synchronizedList的副本(读取时复制而不是写入时复制):

As the OP stated only a snapshot is needed, CopyOnWriteArrayList is probably the best out-of-the-box alternative. An alternative (for cheaper adding, but costlier reading) is just creating a copy of a synchronizedList when traversion is needed (copy-on-read rather than copy-on-write):

List<Foo> originalList = Collections.synchronizedList(new ArrayList());

public void mainThread() {
    while(true)
        originalList.add(getSomething());
}

public void workerThread() {
    while(true) {
        List<Foo> copiedList;
        synchronized (originalList) {
             copiedList = originalList.add(something);
        }
        for (Foo f : copiedList) process(f);
    }
}

考虑一下,读取时复制的版本可以简化一点,以避免所有synchronized块:

Come to think of it, the copy-on-read version could simplified a bit to avoid all synchronized blocks:

List<Foo> originalList = Collections.synchronizedList(new ArrayList());

public void mainThread() {
    while(true)
        originalList.add(getSomething());
}

public void workerThread() {
    while(true) {
        for (Foo f : originalList.toArray(new Foo[0])) 
            process(f);
    }
}

以下是一个简单的包装,用于读取时复制列表,该包装不使用任何帮助程序,并试图尽可能地细化锁定(我ve故意使它有些过分,接近次优,以表明需要锁定的地方):

Edit 2: Here's a simple wrapper for a copy-on-read list which doesn't use any helpers, and which tries to be as fine-grained in the locking as possible (I've deliberately made it somewhat excessive, bordering on suboptimal, to demonstrate where locking is needed):

class CopyOnReadList<T> {

    private final List<T> items = new ArrayList<T>();

    public void add(T item) {
        synchronized (items) {
            // Add item while holding the lock.
            items.add(item);
        }
    }

    public List<T> makeSnapshot() {
        List<T> copy = new ArrayList<T>();
        synchronized (items) {
            // Make a copy while holding the lock.
            for (T t : items) copy.add(t);
        }
        return copy;
    }

}

// Usage:
CopyOnReadList<String> stuff = new CopyOnReadList<String>();
stuff.add("hello");
for (String s : stuff.makeSnapshot())
    System.out.println(s);

基本上,当您锁定时:

  1. ...在列表中添加一个项目.
  2. ...遍历列表以制作副本.

这篇关于JAVA:用于访问Java中列表的并发控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆