0
点赞
收藏
分享

微信扫一扫

JAVA-集合

程序员阿狸 2022-02-11 阅读 124
java集合

1、不安全

ArrayList、HashSet、HashMap不安全的

2、原因

ArrayList 的add()方法没加synchronized (同步锁)关键字

HashSet 的底层原理是HashMap,add方法调用的就是map的put方法,key就是add的元素,值是Object常量

3、会出现的错误

java.util.ConcurrentModificationException //并发异常

4、解决

1)Vector()

使用Vector()方法 add方法加了synchronized

2)Collections.synchronizedList()

把ArrayList转换成线程安全的集合,数据量小的

3)使用CopyOnWriteArrayList<>() 多线程

CopyOnWriteArrayList() 原理就是先加锁,然后复制原先数据。获得原先数据的长度加一,为现在新的数据,原数据供大家读,不能写
 等新的数据设置进去后。释放锁,后面的人读新的数据并且,用新的数据再去做写入。

总结:

ArrayList()----> CopyOnWriteArrayList();

HashSet()----->CopyOnWriteArraySet();

HashMap()----->ConcurrentHashMap<>();

代码:

package com.cb.demo.example;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* 请举例说明集合类是不安全的
*
* 1 故障现象
* java.util.ConcurrentModificationException
* 2 导致原因
*
* 3 解决方案
* 1)使用Vector() add方法加synchronized 保证数据一致性,性能下降
* 2)使用Collections.synchronizedList() 把ArrayList转换成线程安全的集合,数据量小的 单线程
* 3)使用CopyOnWriteArrayList<>() 多线程
* 4 优化建议
*
*
*
* 总结
* 写时复制
* CopyOnWrite容器即写时复制的容器,往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,
* 复制出一个新的容器Object[] newElements,然后新的容器Object[] new Elements里面添加元素,添加元素之后
* 再将原容器的引用指向新的容器setArray(newElements);这样锁的好处是可以对CopyOnWrite容器进行并发的读
* 而不需要加锁,因为当前容器不会添加任何元素,所以CopyOnWrite容器也是一中读写分离的思想,读和写不同的容器
*
*
* ArrayList 有序有重复
* Hash 无序无重复
*/

public class NotSafeDemo {
public static void main(String[] args) {


/**
*
*
*
* HashMap 初始值大小是16,默认加载因子是0.75 加载因子一般够用。但是初始值大小够用
*
* new 一个HashMap初始大小是16,当大小到达16*0.75=12是,会自动扩容 ,每次扩容为2^n+1 2^4=16 2^5= 32
*
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* * (16) and the default load factor (0.75)
*
* ArrayList扩容为原来的一半,HashMap扩容为原来的一倍
*
*
* Node<K,V>[] tab; Node<K,V> p; int n, i;
*
* Node<K,V> next;
* node节点,数组+(单向)链表
*/

Map<String,String> map=new ConcurrentHashMap<>();//Collections.synchronizedMap();//new HashMap<>();
for (int i = 0; i <30 ; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
System.out.println(map);
},String.valueOf(i)).start();
}

new HashMap<>();
}

private static void setNotSafe() {
/**
* HashSet 底层是HashMap(); add方法调用的就是map的put方法,key就是add的元素,值是Object常量
*
* public HashSet() {
* map = new HashMap<>();
* }
*
* public boolean add(E e) {
* return map.put(e, PRESENT)==null;
* }
*
* private static final Object PRESENT = new Object();
*/

Set<String> set= new CopyOnWriteArraySet();//Collections.synchronizedSet(new HashSet<>());//new HashSet<>();
for (int i = 0; i <30 ; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
}

private static void listNotSafe() {
/* List<String> list=Arrays.asList("a","b","c");
list.forEach(System.out::println);
*/


/**
* public synchronized boolean add(E e) Vector的add方法加了 synchronized 所有并发add不会报错 但是性能下降
*
* public boolean add(E e) ArrayList的add方法没有加 synchronized 所以并发add会报错
*
*
* CopyOnWriteArrayList() 原理就是先加锁,然后复制原先数据。获得原先数据的长度加一,为现在新的数据,原数据供大家读,不能写
* 等新的数据设置进去后。释放锁,后面的人读新的数据并且,用新的数据再去做写入。
* public boolean add(E e) {
* final ReentrantLock lock = this.lock;
* lock.lock();
* try {
* Object[] elements = getArray();
* int len = elements.length;
* Object[] newElements = Arrays.copyOf(elements, len + 1);
* newElements[len] = e;
* setArray(newElements);
* return true;
* } finally {
* lock.unlock();
* }
* }
*
*/


List<String> list=new CopyOnWriteArrayList<>();//Collections.synchronizedList(new ArrayList<>()); //new ArrayList<>(); //new Vector<>();

for (int i = 0; i <30 ; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}

}
举报

相关推荐

0 条评论