java 集合不安全问题
ArrayList(线程不安全)
1. arraylist 底层实现
数组 初始长度为10
2. arraylist 线程不安全case
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}).start();
}
}
出现现象
java.util.ConcurrentModificationException(并发修改异常)
导致原因
并发争枪修改导致。
参考花名册,一个人正在写,另一个人过来抢夺,导致数据不一致异常
解决办法
// 解决一
// List<String> list = new Vector()
// ArrayList 线程不安全,效率高
// Vector 线程安全,效率低
// Vector 底层源码中加了 synchronized
public static void main(String[] args) {
List<String> list = new Vector<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}).start();
}
}
// 解决二
// List<String> list = Collections.synchronizedList(new ArrayList<>());
// 性能不高
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 3; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}).start();
}
}
// 解决三
// List<String> list = new CopyOnWriteArrayList<>();
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}).start();
}
}
解决方法三:
List<String> list = new CopyOnWriteArrayList<>();
// 写时复制
/**
* CopyOnWrite 容器即写时复制容器。往一个容器添加元素时,不直接往当前容器Object[] 添加,而是先将当前容器
* Object[] 进行Copy, 复制出一个新容器 Object[] newElements, 然后新的容器 Object[] newElements
* 里添加元素,添加完元素之后,再将原容器的引用指向新的容器 setArray(newElements); 这样做的好处是可以对
* CopyOnWrite 容器进行并发读, 而不需要加锁,因为当前容器不会添加任何元素。 所以CopyOnWrite 容器也是一
* 种读写分离的思想,读和写不同容器。
*/
// 源码
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try{
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyof(element, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
HashSet(线程不安全)
与上面同理
Collections.synchronizedSet(new HashSet())
// 性能不高
new CopyOnWriteArraySet()
hashset 底层 hashmap
key add 的值
value object present = new object();
HashMap(线程不安全)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NzPnmHO7-1609729333684)(C:\Users\pikaqiu\AppData\Roaming\Typora\typora-user-images\1609727707851.png)]
Collections.synchronizedMap(new HashMap())
// 性能不高
HashTable(线程安全)
内部有上锁的控制 synchronized
底层实现是哈希表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q2gDE4Tc-1609729333690)(C:\Users\pikaqiu\AppData\Roaming\Typora\typora-user-images\1609727341710.png)]
ConcurrentHashMap(线程安全)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GjyBmKks-1609729333696)(C:\Users\pikaqiu\AppData\Roaming\Typora\typora-user-images\1609728182225.png)]
对于hashtable,hashmap,concurrenthashmap 如何选择
优先选择hashmap, 如何不是多个资源访问一个线程的情况,优先选用hashmap, 局部变量,不是全局变量
(线程安全)
[外链图片转存中…(img-GjyBmKks-1609729333696)]
对于hashtable,hashmap,concurrenthashmap 如何选择
优先选择hashmap, 如何不是多个资源访问一个线程的情况,优先选用hashmap, 局部变量,不是全局变量
是全局变量,多个线程共享访问选择ConcurrentHashMap