[英]Java Synchronized Collections - what is the value?
以下代码非常非常快地触发了 ConcurrentModificationException:
import java.util.*;
public class SynchFail {
static List<Integer> LIST = new ArrayList<Integer>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
LIST.add(1);
}
}}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
List<Integer> syncList = Collections.synchronizedList(LIST);
synchronized(syncList) {
for (Integer thisInt : syncList) {
}
}
}
}}).start();
}
}
...而以下行为应如此:
import java.util.*;
public class SynchSucceed {
static List<Integer> LIST = new ArrayList<Integer>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized(LIST) {
LIST.add(1);
}
}
}}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized(LIST) {
for (Integer thisInt : LIST) {
}
}
}
}}).start();
}
}
...我的理解是,同步的 collections 是为了防止在这种情况下发生ConcurrentModificationException
(但显然他们没有)。
鉴于此:我应该在哪里使用这些?
在第一个代码片段中,您没有遵循synchronizedList
文档中的说明:
为了保证串行访问,对后备列表的所有访问都通过返回的列表完成是至关重要的。
在另一个线程中,您通过原始LIST
添加到列表中,而不是“返回列表”。 LIST
只是一个普通的ArrayList
并且在其上调用add
不会获得任何锁或类似的东西,因此在迭代过程中仍然可以成功调用add
。
如果你这样做了:
final static List<Integer> LIST = Collections.synchronizedList(new ArrayList<>());
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
LIST.add(1);
}
}}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized(LIST) {
for (Integer thisInt : LIST) {
}
}
}
}}).start();
}
然后它不会抛出 CME。 当您在同步列表上调用add
时,它会尝试获取LIST
上的内在锁。 如果迭代正在进行,则锁可能已经被另一个线程持有(因为你在那里做了synchronized (LIST) {... }
),所以它会等到迭代结束。 将此与第二个代码片段进行比较,并注意这如何使您免于在add
调用周围编写额外的synchronized (LIST) {}
块。
几件事:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.