List不安全
问题:多线程情况下操作类是不安全的。
/**
* @author
* @Date 2022/7/16
* @apiNote
*/
public class Test {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString());
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
结果:
ConcurrentModificationException:并发修改异常
解决方案:
- List list=new Vector();
- List list=Collections.sychronized(new ArrayList());
- List list=new CopyOnWriteArrayList();//copyOnwrite写入时复制,在多线程调用的时候,查询是固定的,写入时会一并覆盖,避免造成数据问题。
CopyOnWriteArrayList 数据结构和 ArrayList 是一致的,底层是个数组,只不过 在对数组进行操作的时候,基本会分四步走:
1.加锁;
2.从原数组中拷贝出新数组;
3.在新数组上进行操作,并把新数组赋值给数组容器;
4.解锁
除了加锁之外,CopyOnWriteArrayList 的底层数组还被 volatile 关键字修饰,意思是一旦数组被修改,其它线程立马能够感知到,代码如下:
结果:
set不安全
示例:
/**
* @author
* @Date 2022/7/16
* @apiNote
*/
public class SetTest {
public static void main(String[] args) {
Set<String> set=new HashSet<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(1,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
结果:
解决:
- Set =Collections.sychronizedSet(new HashSet);
- Set set=new CopyOnWriteArraySet();
结果:
hashSet的底层原理:
hashSet的底层还是HashMap,
set.add就是,所以hashSet的Key是不重复:
Map不安全
/**
* @author
* @Date 2022/7/16
* @apiNote
*/
public class Test {
public static void main(String[] args) {
Map<String,Object> map=new HashMap<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(1,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
结果:
解决:利用concurrentHashMap()