JAVA:用于访问java中列表的并发控制

pie*_*154 5 java list thread-safety

我有一个多线程应用程序,它有一个只有主线程更新(写入)的centrlaised列表.然后我有几个其他线程需要定期检索当前状态的列表.有没有一种方法可以让我这样做?

gus*_*afc 12

这取决于您希望如何限制并发性.最简单的方法可能是使用CopyOnWriteArrayList.从中获取迭代器时,该迭代器将镜像列表查看迭代器创建时的时间点 - 后续修改对迭代器不可见.好处是它可以应对相当多的争用,缺点是添加新物品相当昂贵.

另一种做法是锁定,最简单的方法是Collections.synchronizedList在迭代时将列表包装并在列表上进行同步.

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

编辑:由于OP声明只需要一个快照,CopyOnWriteArrayList可能是最好的开箱即用的替代方案.另一种选择(更便宜的添加,但更昂贵的阅读)只是创建一个synchronizedList需要traversion时的副本(copy-on-read而不是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:想想看,复制读取版本可以简化一点以避免所有synchronized块:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2:这是一个简单的包装,用于读取副本,不使用任何助手,并试图在锁定中尽可能细粒度(我故意使它有些过分,接近于次优,以证明需要锁定的地方):

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);
Run Code Online (Sandbox Code Playgroud)

基本上,当你在以下时锁定:

  1. ...将项目添加到列表中.
  2. ...遍历列表以制作它的副本.