首页 / JAVA / Java中集合的线程安全问题
Java中集合的线程安全问题
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java中集合的线程安全问题,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2541字,纯文字阅读大概需要4分钟。
内容图文
![Java中集合的线程安全问题](/upload/InfoBanner/zyjiaocheng/1334/36278ec71cc448d59068245ee56fe0ff.jpg)
常用的集合类型如ArrayList,HashMap,HashSet等,在并发环境下修改操作都是线程不安全的,会抛出
java.util.ConcurrentModificationException
异常,这节主要记录如何在并发环境下安全地修改集合数据。
List
举个ArrayList线程不安全的例子:
public class CollectionTest {
public static void main(String[] args) {
List<String> data = new ArrayList<>();
IntStream.range(0, 30).forEach(
i -> new Thread(() -> data.add(String.valueOf(i)), String.valueOf(i)).start()
);
System.out.println(data);
}
}
上面例子中,有30个线程对data进行修改操纵,多运行几次上面的程序,控制台便会抛出java.util.ConcurrentModificationException
异常,是因为多个线程并发争抢修改data导致,当一个线程正在写入但还未写完时,另一个线程抢夺写入,这便导致了数据异常。
- 要解决这个问题,主要有以下三种方法:
1. 使用Vector:
public class CollectionTest {
public static void main(String[] args) {
List<String> data = new Vector<>();
IntStream.range(0, 30).forEach(
i -> new Thread(() -> data.add(String.valueOf(i)), String.valueOf(i)).start()
);
System.out.println(data);
}
}
Vector类的add方法是通过加同步锁来实现线程安全的,源码如下。
2.使用Collections
工具类的synchronizedList
方法:
public class CollectionTest {
public static void main(String[] args) {
List<String> data = Collections.synchronizedList(new ArrayList<>());
IntStream.range(0, 30).forEach(
i -> new Thread(() -> data.add(String.valueOf(i)), String.valueOf(i)).start()
);
System.out.println(data);
}
}
其本质还是通过同步锁来解决线程安全问题。
3. 使用CopyOnWriteArrayList
:
public class CollectionTest {
public static void main(String[] args) {
List<String> data = new CopyOnWriteArrayList<>();
IntStream.range(0, 30).forEach(
i -> new Thread(() -> data.add(String.valueOf(i)), String.valueOf(i)).start()
);
System.out.println(data);
}
}
查看CopyOnWriteArrayList
类的add
方法源码,发现它使用了可重入锁解决线程安全问题。
上面方法的源码使用了写时复制的思想(CopyOnWrite
):往一个容器添加元素的时候,不直接往当前容器Object[]
添加,而是先将当前容器Object[]
进行复制,复制出一个新的容器Object[] newElements
,然后往新的容器Object[] newElements
里添加新的元素。添加完后,再将原容器的引用指向新的容器(即源码中的setArray(newElements)
)。
这种做法的好处是可以对CopyOnWrite
的容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以这也是一种读写分离的思想,即读和写的容器是不同的容器。
上面这三种解决办法中,更推荐使用CopyOnWriteArrayList
。
Set
HashSet在并发下修改也会出现线程安全问题。解决办法同样可以通过Collections#synchronizedSet
和CopyOnWriteArraySet
解决,过程和上述类似,所以不再赘述。
Map
HashMap在并发环境下修改时的线程安全问题同样可以通过Collections.synchronizedMap
解决。此外并没有所谓的CopyOnWriteHashMap
,线程安全的HashMap可以使用ConcurrentHashMap
:
public class CollectionTest {
public static void main(String[] args) {
Map<String, String> data = new ConcurrentHashMap<>();
IntStream.range(0, 30).forEach(
i -> new Thread(() -> data.put(String.valueOf(i), String.valueOf(i)), String.valueOf(i)).start());
System.out.println(data);
}
}
原文:https://www.cnblogs.com/jason47/p/14410529.html
内容总结
以上是互联网集市为您收集整理的Java中集合的线程安全问题全部内容,希望文章能够帮你解决Java中集合的线程安全问题所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。