本文探讨了并发编程中遇到的一个常见问题:在使用 foreach 遍历时删除 list 中的元素可能导致的并发异常。通过引入 synchronizedList 方法,演示了解决并发访问和线程安全的方法,并提供了代码示例来说明如何正确地处理此类情况。
package collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 测试快速失败模型,不加锁的情况下,在foreach遍历list的时候删除list中的元素
*
*/
public class ListTest {
private static List<String> list = Collections.synchronizedList(new ArrayList<String>());
static{
//初始化List
for (int i = 0; i < 100; i++) {
list.add(String.valueOf(i));
}
}
public static void main(String[] args) {
/*
* 快速失败一:foreach中删除元素
*/
// for (String string : list) {
// System.out.println(string);
// if(string.equals("50")){
// list.remove(string);
// }
// }
//解决办法
new Thread(new Runnable(){
@Override
public void run() {
synchronized (list) {
for (String string : list) {
System.out.println(string);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (list) {
list.remove("50");
}
}
}).start();
}
}
synchronizedList
public static <T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全的)列表。为了保证按顺序访问,必须通过返回的列表完成所有对底层实现列表的访问。
在返回的列表上进行迭代时,用户必须手工在返回的列表上进行同步:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
不遵从此建议将导致无法确定的行为。
如果指定列表是可序列化的,则返回的列表也将是可序列化的。
参数:
list - 被“包装”在同步列表中的列表。
返回:
指定列表的同步视图。