跑起一個程式,并不難;難的是,能讓程式跑多遠!—— 一顆剽悍的種子

JUC并發系列
JUC并發系列(一):什么?聽說你搞混了并發和并行
JUC并發系列(二):詳解Condition實作精準通知喚醒
JUC并發系列(三):面試問并發,一問鎖就懵(怒肝一篇透徹理解鎖,面試不慌)
一、ArrayList非執行緒安全
在之前的多執行緒系列中有講過ArrayList在多執行緒下并不安全,
深入多執行緒十:只有從不同案例中,才能深刻體會多執行緒的不安全,從而才能更好的解決
沒看過的小伙伴也沒關系,我們再把代碼拿出來回顧一下,
1.1 ArrayList非執行緒安全代碼示例
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
運行結果
可以看到集合的長度添加的數量并不是我們預期的長度,
而是可能會出現覆寫,
在多執行緒下集合ArrayList是不安全的,

二、Vector解決ArrayList非執行緒安全
是不是很好奇,這里為何會提Vector,不只因為Vector是執行緒安全的,也因為ArrayList都來自List介面,所以可能是你學習時最常接觸的,也可能是你開發中解決 ArrayList 非執行緒問題最常用的,當然也會是你脫口而出的面試答案,
但是,但是…
如果你只會 Vector 是遠遠不夠的,為什么這么說,問你個小問題!
你覺得是 ArrayList 在JDK中先出現的還是 Vector ?
你的回答肯定是先 ArrayList 后再 Vector 啦,這還有問的,Vector不正是為了解決ArrayList的非執行緒問題的,
但是答案可能恰恰相反,在 JDK1.0 中就加入了 Vector,而ArrayList是在JDK1.2才加入的,所以 Vector是老生了,ArrayList才是那個新生(當然1.2也不算新啦),


2.1 Vector解決ArrayList非執行緒代碼示例
Vector解決起來很簡單,只需把ArrayList關鍵字換成 Vector,
Vector<String> list = new Vector<String>();
Vector除了
public class Demo {
public static void main(String[] args) {
Vector<String> list = new Vector<String>();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
運行結果

2.2 Vector雖好,但是慎用
Vector雖然是一個執行緒安全的List,但是它的執行緒安全實作方式是對所有操作都加上了synchronized關鍵字,這種方式嚴重影響效率.所以并不推薦使用Vecto,

2.3 面試回答Vector,并不是一個加分項,只是一個答案
除了慎用,當邂逅面試時,如果僅僅答出Vector其實并不能給你加分,因為Vector算是古老的關鍵字了,只能算是一個答案,
但是如果你能回答Vector后,還能說出下面解決的辦法,那么就可以體現你知識面的廣度了,
三、 synchronizedList解決ArrayList非執行緒安全
synchronizedList是Collections提供的一個方法,解決起來也很簡單,
List<String> list = Collections.synchronizedList(new ArrayList());
3.1 synchronizedList解決ArrayList非執行緒代碼示例
public class Demo {
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList());
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
運行結果

3.2 synchronizedList的優缺點
synchronizedList 的寫操作性能比下面即將要介紹的 CopyOnWriteArrayList 在多執行緒操作時性能好很多,但讀操作采用了synchronized關鍵字,所以讀沒有CopyOnWriteArrayList要好,
只要有synchronized的地方,也就是有加鎖的地方,性能方面當然就沒有不加鎖好,
所以沒有最好的方法,只有最合適的應用場景,
四、 CopyOnWriteArrayList
CopyOnWriteArrayList 主要在于 CopyOnWrite 寫入時復制(簡稱COW),是計算機程式設計中的一種優化策略,
寫入時復制其思想是在多執行緒下同時讀取同一個資源時會共同獲取指標指向的資源,但當某些執行緒操作(修改)同一個資源時,才會真正復制一份副本,而其他執行緒訪問最初資源不變,
可以簡單的理解是 在寫入的時候避免覆寫而造成資料問題,
4.1 CopyOnWriteArrayList解決ArrayList非執行緒代碼示例
public class Demo {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
運行結果

4.2 總結CopyOnWriteArrayList
綜合上面,我想你都能總結 CopyOnWriteArrayList了,CopyOnWriteArrayList在讀方面好于Vector,synchronizedList,但讀寫性能不如synchronizedList,
五、最后
最后的最后,為了更好的閱讀體驗,我把想說的話都放在了下面,嘿嘿,
我是一顆剽悍的種子 把我會的,認真的分享 是我寫博客一直不變的信條,
如果你能看到這篇博文,說明咱們還是很有緣的;希望能帶給你一些許幫助,創作的不易, 把我文章的知識帶走,你的三連留下,點贊,評論,關注,是我最大的動力,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/126616.html
標籤:其他
上一篇:微盟程式員刪庫跑路,被判刑六年!
下一篇:作業系統漏洞檢測與利用
