JUC——安全容器類(CopyOnWriteArrayList,CopyOnWriteArraySet 和 ConcurrentHashMap)
引入
在多執行緒下,List ,Set ,Map 都是不安全的。
先拿List舉個例子。
import java.util.*;
/**
* @ClassName ListTest
* @Description
* @Author SkySong
* @Date 2020-10-11 22:26
*/
@SuppressWarnings("ALL")
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {//開10條執行緒去修改list
new Thread(()->{
String uuid = UUID.randomUUID().toString().substring(0,5);
list.add(uuid);
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
用多個執行緒同時去修改一個 List 列表。
報了 併發修改異常,這一點是毋庸置疑的。
(java.util.ConcurrentModificationException 執行緒併發修改異常。)
解決方案
併發問題,首先想到的是 synchronize。
所以有了我們的第一個解決方案: new Vector()
import java.util.*;
/**
* @ClassName ListTest
* @Description
* @Author SkySong
* @Date 2020-10-11 22:26
*/
@SuppressWarnings("ALL")
public class ListTest {
public static void main(String[] args) {
List<String> list = new Vector<String>();
for (int i = 1; i <= 10; i++) {//開10條執行緒去修改list
new Thread(()->{
String uuid = UUID.randomUUID().toString().substring(0,5);
list.add(uuid);
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
來看看 Vector 的 addElement() 方法:
這是最傳統的方法了。
我們還可以藉助工具類 Collections(集合老大哥)
import java.util.*;
/**
* @ClassName ListTest
* @Description Collections
* @Author SkySong
* @Date 2020-10-11 22:26
*/
@SuppressWarnings("ALL")
public class ListTest {
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <= 10; i++) {//開10條執行緒去修改list
new Thread(()->{
String uuid = UUID.randomUUID().toString().substring(0,5);
list.add(uuid);
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
我們藉助工具類 Collections 把 new 出來的 ArrayL<>() 變成一個安全的。
接下來便是我們的主角了:JUC解決方案——COW計算機優化策略
CopyOnWriteArrayList
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @ClassName ListTest
* @Description java.util.ConcurrentModificationException 執行緒併發修改異常。
* @Author SkySong
* @Date 2020-10-11 22:26
*/
@SuppressWarnings("ALL")
public class ListTest {
public static void main(String[] args) {
/**
* 解決執行緒併發問題:
* 1.List<String> list = new Vector<String>();
* 2.List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3.List<String> list = new CopyOnWriteArrayList<>();
*/
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 10; i++) {//開10條執行緒去修改list
new Thread(()->{
String uuid = UUID.randomUUID().toString().substring(0,5);
list.add(uuid);
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
來初步感受一下 CopyOnWriteArrayList 的設計思想:
從 CopyOnWriteArrayList 的 add() 方法中可以看出,他是將 陣列資源 複製一版給呼叫者,呼叫者操作的是複製版,這樣就避免了 多個執行緒共同操作一個 “母版” 的情況。
說了這麼多,那麼JUC方案的優勢是什麼呢?
CopyOnWriteArrayList 的 add() 方法避免使用了 synchronized ,而是使用了靈活性較高的 Lock 鎖,在加上 COW 優化策略,使其效率有了很大程度的提高。
有了 List 當然 少不了 Set
CopyOnWriteArraySet
Set 和 List 都是 Collection老大哥的手下,所以很像。
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ClassName SetTest
* @Description java.util.ConcurrentModificationException
* @Author SkySong
* @Date 2020-10-12 22:57
*/
@SuppressWarnings("ALL")
public class SetTest {
public static void main(String[] args) {
/**
* 解決方案:
* 1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2.Set<String> set = new CopyOnWriteArraySet<>();
*/
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 10; i++) {//開10條執行緒去修改set
new Thread(()->{
String uuid = UUID.randomUUID().toString().substring(0,5);
set.add(uuid);
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
這裡提了一下 HashSet ,簡單聊聊:
其實 HashSet 底層就是個 HashMap。
- HashMap 的 key 是不允許重複的,有了這一點就不難聯想了。
HashSet 的 add() 方法:
這裡的 value 值就是一個靜態常量,不用太在意。
List 和 Set 都說的了, 容器三劍客 怎麼能少了 Map。
ConcurrentHashMap
在多執行緒併發的情況下 Map 也是不安全的。
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @ClassName MapTest
* @Description
* @Author SkySong
* @Date 2020-10-13 19:44
*/
public class MapTest {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
for (int i = 1; i <= 10; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName().toString(), UUID.randomUUID().toString());
System.out.println(map);
}).start();
}
}
}
同樣會報如下異常:
這裡補充一點HashMap的知識:
解決思路
這裡當然可以用 Collections.synchronizedMap(new HashMap<>());
但這不是我們今天的主角。 JUC 才是我們今天的主角。
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<>();
for (int i = 1; i <= 10; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName().toString(), UUID.randomUUID().toString());
System.out.println(map);
}).start();
}
}
關於 ConcurrentHashMap 的巧妙之處有很多。我們下次再聊!
相關文章
- HashSet、TreeSet、CopyOnWriteArraySet和CopyOnWriteArrayList
- Java JUC CopyOnWriteArrayList 解析Java
- 併發容器之CopyOnWriteArrayList
- java併發程式設計工具類JUC第八篇:ConcurrentHashMapJava程式設計HashMap
- 併發-7-同步容器和ConcurrentHashMapHashMap
- JUC之Callable介面回顧和JUC輔助類
- 【JUC】JDK1.8原始碼分析之ConcurrentHashMap(一)JDK原始碼HashMap
- 淺談CopyOnWriteArraySet
- JUC併發程式設計學習(五)集合類不安全程式設計
- Java JUC ThreadLocalRandom類解析Javathreadrandom
- JUC鎖種類總結
- Qt容器類QList、QLinkedList和QVector類QT
- ConcurrentHashMap執行緒安全嗎?HashMap執行緒
- CopyOnWriteArrayList
- Java併發指南14:Java併發容器ConcurrentSkipListMap與CopyOnWriteArrayListJava
- 集合類HashMap,HashTable,ConcurrentHashMap區別?HashMap
- 併發容器之ConcurrentHashMap(JDK 1.8版本)HashMapJDK
- 【Java】ConcurrentHashMap執行緒安全技巧JavaHashMap執行緒
- 從原始碼分析ConcurrentHashMap執行緒安全和高效的特性原始碼HashMap執行緒
- JUC包中原子類使用及其原理
- JUC 常用4大併發工具類
- 剖析 CopyOnWriteArrayList
- ConcurrentHashMap一定執行緒安全?HashMap執行緒
- 兩種Java容器類List和Set分析Java
- java 容器類Java
- JUC(3)---CountDownLatch、CyclicBarrier和AQSCountDownLatchAQS
- 認識CopyOnWriteArrayList
- CopyOnWriteArrayList詳解
- 4.3 容器類Widget- 裝飾類容器DecoratedBox
- ArrayList執行緒不安全怎麼辦?(CopyOnWriteArrayList詳解)執行緒
- 容器安全公開課 | 揭秘容器黑產,探討容器安全解決方案
- ConcurrentHashMap 原始碼分析03之內部類ReduceTaskHashMap原始碼
- CopyOnWriteArrayList原始碼解析原始碼
- Java併發-CopyOnWriteArrayListJava
- java集合之CopyOnWriteArrayListJava
- 【JUC】JUC鎖框架綜述框架
- 聊聊JUC包下的底層支撐類-AbstractQueuedSynchronizer(AQS)AQS
- 基於容器特點和傳統網路安全能力進行容器雲安全規劃設計