集合不安全
集合不安全
大家很容易知道哪些集合安全哪些不安全,但是很多时候都是局限于知道,而不清楚细节。所以这就是展示一些细节的地方。
先说结论:
List、Set、Map都不安全
以List为例
private static void ShowList(){
//看源码
List<String> list = new ArrayList<>();
list.add("a");
list.add("a");
list.add("a");
//consumer接口
//list.forEach(System.out::println);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
这段代码就表现出了List不安全的性质,将会出现一个异常
java.util.ConcurrentModificationException
原因是: 迭代器的modCount和expectedModCount的值不一致
就是线程安全异常。
不要停留在仅知道List不安全,要能说能写出这段代码。
其中注释的地方有用到接口consumer,简单理解就是lambda表达式简写。明显能看出将foreach循环压缩到了一行。
寻找原因,即找源码,看是否有synchronized 修饰
出现了问题就要解决,共有三种解决方案:
//3.1 List<String> list = new Vector<>();
//3.2 List<String> list = Collections.synchronizedList(new LinkedList<>());
//3.3 List<String> list1 = new CopyOnWriteArrayList<>();
第一种是用Vector,第二种是用Collections工具类的方法,第三种用写时复制方法。
ArrayList底层Object[]数组、Set底层HashMap、HashMap底层链表散列
Set和List类似
Map则是特殊的
//Map<String, String> map = new ConcurrentHashMap<>();
最后说一下简单说下写时复制:
写入时复制是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。
此作法的主要优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作是可以共享同一份资源。
就是资源A 要被修改时创建一个副本A+,修改时其他进程看的仍是原资源A,当修改完后,引用指向资源A+,A被销毁。确保了在修改时数据的安全。
总结就是确保了线程安全同时保障了效率。
上一篇: 集合不安全
下一篇: 将一个八位的二进制数转换为十进制数