面试题
- List 底层是数组,初始大小10,Object类型,扩容加一半,通过array.copyof复制原来的数组,线程是不安全的。
- 初始值为10,第一次扩容15,第二次扩容22。
- Map 底层是数组+链表,初始大小16,Object类型,扩容加一倍,每次next+1,key的hash值一样则加在链上。线程是不安全的。
- hashSet,底层是hashMap,值是new了一个Object对象。
- Collections和Collection区别:Collections是集合工具类,Collection是集合。使用Collections.synchronized集合可以给集合List、Map、Set加锁,所以这些集合是不安全的。
List、Map、Set为什么线程是不安全的,你是怎么解决的,请解释?
List故障现象
- 代码
List list = new ArrayList(); for (int i = 0; i < 10; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 9)); System.out.println(list); }, "线程" + String.valueOf(i)).start(); }
- 高并发下出了异常
出错ConcurrentModificationException - 图示
导致原因
- 高并发(多线程)下操作同一数组出现 并发修改异常(ConcurrentModificationException)。
解决方法
- Vector()
- 代码
List list = new Vector(); for (int i = 0; i < 30; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 9)); System.out.println(list); }, "线程" + String.valueOf(i)).start(); }
- 结果:没有出异常
- vector为什么能解决高并发异常,源码解析,在add方法中加了锁
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
- 代码
- Collections.synchronizedList(new ArrayList<>()
- 代码
List list = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i < 30; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 9)); System.out.println(list); }, "线程" + String.valueOf(i)).start(); }
- 结果:没有出异常
- 解决原因:直接给数组add加锁
public boolean add(E e) { synchronized (mutex) {return c.add(e);} }
- 代码
- CopyOnWriteArrayList()
- 代码
List list = new CopyOnWriteArrayList(); for (int i = 0; i < 30; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 9)); System.out.println(list); }, "线程" + String.valueOf(i)).start(); }
- 结果:
- 解决原因:数组add方法加了lock锁
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(); } }
- 代码
- 集合关系
Map故障现象
- 代码
Set set = new HashSet(); for (int i = 0; i < 30; i++) { new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0, 9)); System.out.println(set); }, "线程" + String.valueOf(i)).start(); }
- 错误截图
- 解决方式
- Collections.synchronizedList(new Arrayset<>() 原因同上List
- CopyOnWriteArraySet() 原因同上List
Set故障现象
- 代码
Map map = new HashMap(); for (int i = 0; i < 30; i++) { new Thread(()->{ map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 9)); System.out.println(map); }, "线程" + String.valueOf(i)).start(); }
- 错误截图
- 解决方式
- Collections.synchronizedMap(new HashMap<>() 原因同上List
- ConcurrentHashMap() add方法加了锁sychronized