面试题—举例说明List 、Set、HashMap是线程不安全的
大厂面试题
1.我们知道 ArrayList 是线程不安全的,请编写一个不安全的案例并给出解决方案?
首先,我们会想到,用了这么久的List,也做了些项目用到了List,并没有遇到过不安全的问题呀!那其实是我们用的场景只是在单线程下,如果是在高并发(多线程)的情况下,便会出现一些线程不安全的问题,下面我们来看个例子:
package com.containernotsafe.test;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @description: 集合不安全问题
* @author: Mr.Li
* @create: 2019-09-24 18:56
**/
public class ContainerNotSafeDemo {
public static void main(String[] args) {
//List<String> list = new ArrayList<>(); 导致线程不安全
//3种解决方案
//List<String> list = new Vector<>();
//List list = Collections.synchronizedList(new ArrayList<>());
List list = new CopyOnWriteArrayList();
for (int i = 0; i < 30; i++) {
new Thread(()->{
list.add(String.valueOf(new Random().nextInt(100)));
System.out.println(list);
},String.valueOf(i)).start();
}
/*1.故障现象
* 报错java.util.ConcurrentModificationException
* 2.导致原因
* 并发争抢修改导致
* 3.解决方案
* new Vector();
* Collections.synchronizedList(new ArrayList<>());
* new CopyOnWriteArrayList<>();
* 4.优化建议
* 在读多写少的时候推荐使用 CopeOnWriteArrayList 这个类
*/
}
}
CopyOnWriteArrayList说明:
CopyOnWrite容器即写时复制容器。往一个容器添加元素时,不直接往当前容器Object[] 进行Copy,复制出一个新的容器Object[] newElements, 然后新的容器setArray(newElements); 这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素,所以CopyOnWrite容器也是一直读写分离的思想,读和写是不同的容器。
CopyOnWriteArrayList 下的add方法:
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();
}
}
2.Set 是线程不安全的,请编写一个不安全的案例并给出解决方案?
private static void set() {
//Set<String> set = new HashSet<>();导致线程不安全
//2种解决方案
//Set<String> set = Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
//HashSet 底层是HashMap
}
3.HashMap 是线程不安全的,请编写一个不安全的案例并给出解决方案?
private static void map() {
//Map<String,String> map = new HashMap<>();导致线程不安全
//2种解决方案
// Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
Map<String,String> map = new ConcurrentHashMap<>();
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();
}
}
每日一言:
今天你不努力争取自己想要的生活
明天你只能花更多的时间应付自己不想要的生活。