JUC并发编程——解决集合类不安全
1、并发集合
在JDK1.5中引入了java.util.concurrent包,在该包中定义了一组线程安全的集合,称为并发集合, 这些集合可以作为同步集合的替代品。
| 非线程安全的集合 | 并发集合 | 共同接口 |
|---|---|---|
| ArrayList | CopyOnWriteArrayList | List |
| LinkedList | ConcurrentLinkedQueue | Queue |
| HashSet | CopyOnWriteArraySet | Set |
| TreeSet | ConcurrentSkipListSet | SortedSet |
| HashMap | ConcurrentHashMap | Map |
| TreeMap | ConcurrentSkipListMap | SortedMap |
参考:http://www.bjpowernode.com/javathread/1151.html
2、List 不安全
List集合不是线程安全的,在多线程环境中使用这些集合可能会出现数据不一致的情况,或者产生异常。
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i < 10; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
查看异常:并发异常 ConcurrentModificationException

由上可知,并发情况下,ArrayList 不安全。
解决 List 不安全
方法一:Vector 集合
public class ListTest {
public static void main(String[] args) {
List<String> list = new Vector<>();
for (int i = 1; i < 10; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
原因:Vector集合是线程安全,在Vector集合中使用synchronized关键字把方法修饰为同步方法,只允许由一个线程调用其中一个方法。所以又把Vector集合称为同步集合。
Vector集合add()方法源码:

方法二:Collections工具类
在Collections工具类中提供了一组synchronizedXXX()方法可以把不是线程安全的集合转换为线程安全的集合,这也是同步集合。
public class ListTest {
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i < 10; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
方法三:并发集合CopyOnWriteArrayList,并发集合可以作为同步集合的替代品。
public class ListTest {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i < 10; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
CopyOnWriteArrayList 写入操作源码分析:

CopyOnWriteArrayList集合, 该集合在读取数据时完全不用加锁,并且写操作也不会阻塞读操作。从集合类名来看CopyOnWrite就是在写入操作时,进行一次自我复制。即向集合写入数据并不修改原有的内容, 而是把集合中原来的从容复制到一个副本中,向副本中写入数据,写完后再将副本替换原来的数据。
并发集合CopyOnWriteArrayList 比 同步集合Vector与Collections.synchronizedList() 的效率都要高,因为后两种方法都用了synchronized,每次在读数据时都会进行加锁同步,它们读取数据的效率就低。
3、Set 不安全
和 List集合一样,set集合在并发情况下也是不安全的,
解决Set 不安全两个方法:
1、Collections工具类的 synchronizedSet() 方法
2、并发集合 CopyOnWriteArraySet
4、Map 不安全
public class MapTest {
public static void main(String[] args) {
HashMap<Object, Object> map = new HashMap<>();
for (int i = 1; i < 10; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}
发生并发异常:

解决 Map 不安全
1、Collections 同步集合
public class MapTest {
public static void main(String[] args) {
Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
for (int i = 1; i < 10; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}
Collections.synchronizedMap(new HashMap<>()) 可以返回一个线程安全的集合,采用了装饰器模式,在该线程安全的集合内部,先要获得mutex锁,并发效率低。
2、ConcurrentHashMap 集合
public class MapTest {
public static void main(String[] args) {
ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
for (int i = 1; i < 10; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}
ConcurrentHashMap是一种高并发的线程安全的 Map集合。在JDK7前,ConcurrentHashMap 集合内部使用粒度极小的锁来保障线程安全,或者说采用了分段锁协议,默认情况下可以支持16个线程并发操作。在JDK8中对ConcurrentHashMap集合进行了性能提升,采用CAS操作实现线程安全。
本文探讨了Java中集合类在多线程环境下存在的安全问题,并介绍了如何通过使用线程安全的集合类如Vector、CopyOnWriteArrayList以及ConcurrentHashMap等来解决这些问题。
1044

被折叠的 条评论
为什么被折叠?



