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)
基本上,当你在以下时锁定: