摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載引言做的同學們或多或少的接觸過集合框架在集合框架中大多的集合類是線程不安全的比如我們常用的等等我們寫一個例子看為什么說是不安全的例子證明是線程不安全的我們開啟個線程每個線程向
引言本人郵箱:
歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經全部托管github有需要的同學自行下載
做java的同學們或多或少的接觸過Java集合框架.在java集合框架中,大多的集合類是線程不安全的.比如我們常用的ArrayList等等.我們寫一個例子看,為什么說ArrayList是不安全的.
例子1 證明ArrayList是線程不安全的我們開啟100個線程.每個線程向List加100個數據,那么當所有線程執行完成之后應該是10000條,然后就對比一下結果,看看是否為10000條.
public class Demo1 { public static void main(String[] args) throws InterruptedException { Listlist = new ArrayList<>(); Thread[] threads = new Thread[100]; for (int i = 0; i < threads.length; i ++){ threads[i] = new Thread(() -> { for (int j = 0;j < 100; j ++){ list.add(Thread.currentThread().getName() + ":" + j); } }); threads[i].start(); } for (Thread thread : threads){ thread.join(); } System.out.println(list.size()); } }
thread.join(); 是讓主線程等待所有的子線程執行完,才執行接下來的語句
運行結果為9979,而且每次運行結果還不一定是這個數.
當然,我們可以通過學過的知識,在執行list.add是給它加鎖,比如將list.add(Thread.currentThread().getName() + ":" + j);改為synchronized (list){list.add(Thread.currentThread().getName() + ":" + j);}這樣就能保證線程同步了.
可直接用于并發的集合類其實java中已經提供了可直接用于并發的集合類,它們可以在多線程中進行CURD1操作,而且不需要程序員手動加lock或synchronized來保證同步.一般來說,它們分以下兩種:
阻塞式集合(Blocking Collection): 這類集合一般在添加或刪除數據,如果集合已滿或為空時,則調用添加和刪除方法的線程會被阻塞,直接該方法可以成功執行
非阻塞式集合(Non-Blocking Collection):這類集合一般在添加或刪除數據,如果方法不能立即執行時,則會返回Null或拋出異常,但調用該方法的線程不會被阻塞.
這節課我將重點講ArrayBlockingQueue,首先先看一下ArrayBlockingQueue的api,以及區分這些的差別
add(E),offer(E),pub(E)都是這隊列尾部加入元素E,如果隊列不滿,則加入成功,并立即返回.如果隊列滿了,那么
add會拋出IllegalStateException異常
offer立刻返回false
put會讓調用的線程一直等待,直到方法執行成功
offer(E e, long timeout, TimeUnit unit),offer另一種方法,當集合已滿,如果等待時間小于等于0,那么會離開返回false,否則等到指定的時間
poll(),take(),獲取隊列的數據,如果隊列為空,那么
poll 立刻返回null
take 線程等待,直到獲取到數據,或被中斷
poll(long timeout, TimeUnit unit),如隊列為空,當指定時間小于等于,立刻返回null,否則等待指定的時間
peek(): 看一下隊列當前的數據,如果隊列為空,則立即返回null
例子之前我們寫過山治和路飛的故事,在(十二)java多線程之Exchanger的例子中,其實山治和路飛是一個簡單的生產者-消費者模式,只是山治和路飛都要等對方吃完或做完一個才能繼續下一個.現在路飛想出另一個辦法,在廚房和餐桌之間弄一個傳送帶,山治把食物做好之后,直接放傳送帶上,路飛就直接從傳送帶拿食物.傳送帶最多只能放10個食物.ok,開始編碼..
Food 沒有改.
LuFeiRunnable改為
public class LuFeiRunnable implements Runnable{ ArrayBlockingQueuequeue; Random random = new Random(); public LuFeiRunnable(ArrayBlockingQueue queue) { this.queue = queue; } @Override public void run() { while (true){ try { String take = queue.take(); System.out.println("-->路飛拿到 " + take); Thread.sleep(random.nextInt(500)); System.out.println("-->路飛吃完 " + take); } catch (InterruptedException e) { e.printStackTrace(); } } } }
ShanZhiRunnable改為
public class ShanZhiRunnable implements Runnable{ ArrayBlockingQueuequeue; Random random = new Random(); public ShanZhiRunnable(ArrayBlockingQueue queue) { this.queue = queue; } @Override public void run() { while (true){ try { String food = Food.getRandomFood(); System.out.println("==>山治開始做 " + food); Thread.sleep(random.nextInt(500)); System.out.println("==>山治做好了 " + food); queue.put(food); } catch (InterruptedException e) { e.printStackTrace(); } } } }
測試類改為:
public class TestMain { public static void main(String[] args) { ArrayBlockingQueuequeue = new ArrayBlockingQueue<>(10); new Thread(new LuFeiRunnable(queue)).start(); new Thread(new ShanZhiRunnable(queue)).start(); } }
運行結果:
==>山治開始做 椒麻雞 ==>山治做好了 椒麻雞 ==>山治開始做 牛腩煲 -->路飛拿到 椒麻雞 ==>山治做好了 牛腩煲 ==>山治開始做 豆苗炒蝦片 ==>山治做好了 豆苗炒蝦片 ==>山治開始做 火鞭牛肉 -->路飛吃完 椒麻雞 -->路飛拿到 牛腩煲 ==>山治做好了 火鞭牛肉 ==>山治開始做 桃酥雞糕 -->路飛吃完 牛腩煲 -->路飛拿到 豆苗炒蝦片 ==>山治做好了 桃酥雞糕 ==>山治開始做 雞湯煮干絲 -->路飛吃完 豆苗炒蝦片 -->路飛拿到 火鞭牛肉 ==>山治做好了 雞湯煮干絲 ==>山治開始做 菊花豬肝湯 -->路飛吃完 火鞭牛肉 -->路飛拿到 桃酥雞糕 ==>山治做好了 菊花豬肝湯 ==>山治開始做 清香炒悟雞 -->路飛吃完 桃酥雞糕 -->路飛拿到 雞湯煮干絲 -->路飛吃完 雞湯煮干絲 -->路飛拿到 菊花豬肝湯 ==>山治做好了 清香炒悟雞 ==>山治開始做 槐花豬腸湯 -->路飛吃完 菊花豬肝湯 -->路飛拿到 清香炒悟雞 -->路飛吃完 清香炒悟雞 ==>山治做好了 槐花豬腸湯 ==>山治開始做 瑞士排骨 -->路飛拿到 槐花豬腸湯 -->路飛吃完 槐花豬腸湯 ==>山治做好了 瑞士排骨 -->路飛拿到 瑞士排骨 ==>山治開始做 芝麻魚球 -->路飛吃完 瑞士排骨
山治和路飛都很happy,各自都在做自己喜歡做的事情,但是,如果路飛吃到一定階段,吃不下了,會發生什么呢?比如把LuFeiRunnable中的Thread.sleep(random.nextInt(500));改為Thread.sleep(random.nextInt(5000));,然后運行結果,會發現山治做菜速度也變慢了,因為傳送帶的食物放不下,山治必須等路飛吃掉一些,這樣傳送帶才能放下食物.
擴展這就想我們去銀行排隊,醫院取號,或者去各種部門排隊辦業務的時候.如果人來的太多了,那么他們一般的做法就是沒號,要么在網上預約,要么下次早點來.這就是生產者(排隊的人)生產太快,消費者(銀行,醫院等)消費太慢了
ArrayBlockingQueue的父類是BlockingQueue,通過查找BlockingQueue的子類,我們能找到以下這幾個類.
SynchronousQueue跟ArrayBlockingQueue類似,只不過它除了可以用put,offer,take,add,poll,take這幾個方法外,其余的例如isEmpty,size,clear,contains,remove等等,都是無效的,大部分都是直接返回一個固定值.這是因為它是一個沒有容量的隊列.甚至連一個容量都沒有.因此在每次做插入操作的時候,都必須等其他線程做刪除操作.
LinkedBlockingQueue跟ArrayBlockingQueue類似,只是ArrayBlockingQueue是通過數組的方式實現隊列,而LinkedBlockingQueue是通過列表的方式實現隊列.
LinkedBlockingDeque跟LinkedBlockingQueue一樣是用鏈表實現隊形,只是LinkedBlockingDeque為雙向鏈表,可以在頭部或尾部進行添加和刪除操作.
add*,offer*,put*這些增加操作跟LinkedBlockingQueue和LinkedBlockingQueue的add,offer,put是類似的,如果這些方法不帶*,則都是等價與*Last
poll*,take*這些獲取數據操作跟LinkedBlockingQueue和LinkedBlockingQueue的poll,take類似的,如果不帶*,則等價于*Frist
打賞在學習中,我們要能舉一反三.這樣我們就會學的比較快.
如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
C:create 新增,U:update 更新,R:retrieve 讀取,D:delete 刪除 ?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69937.html
摘要:如果隊列已滿,這個時候寫操作的線程進入到寫線程隊列排隊,等待讀線程將隊列元素移除騰出空間,然后喚醒寫線程隊列的第一個等待線程。數據必須從某個寫線程交給某個讀線程,而不是寫到某個隊列中等待被消費。 前言 本文直接參考 Doug Lea 寫的 Java doc 和注釋,這也是我們在學習 java 并發包時最好的材料了。希望大家能有所思、有所悟,學習 Doug Lea 的代碼風格,并將其優雅...
摘要:線程安全的線程安全的,在讀多寫少的場合性能非常好,遠遠好于高效的并發隊列,使用鏈表實現。這樣帶來的好處是在高并發的情況下,你會需要一個全局鎖來保證整個平衡樹的線程安全。 該文已加入開源項目:JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識的文檔類項目,Star 數接近 14 k)。地址:https://github.com/Snailclimb... 一 JDK ...
摘要:整個包,按照功能可以大致劃分如下鎖框架原子類框架同步器框架集合框架執行器框架本系列將按上述順序分析,分析所基于的源碼為。后,根據一系列常見的多線程設計模式,設計了并發包,其中包下提供了一系列基礎的鎖工具,用以對等進行補充增強。 showImg(https://segmentfault.com/img/remote/1460000016012623); 本文首發于一世流云專欄:https...
摘要:在章節中,我們說過,維護了一把全局鎖,無論是出隊還是入隊,都共用這把鎖,這就導致任一時間點只有一個線程能夠執行。入隊鎖對應的是條件隊列,出隊鎖對應的是條件隊列,所以每入隊一個元素,應當立即去喚醒可能阻塞的其它入隊線程。 showImg(https://segmentfault.com/img/bVbgCD9?w=1920&h=1080); 本文首發于一世流云專欄:https://seg...
摘要:前言這篇主要來講解多線程中一個非常經典的設計模式包括它的基礎到拓展希望大家能夠有所收獲生產者消費者模式簡述此設計模式中主要分兩類線程生產者線程和消費者線程生產者提供數據和任務消費者處理數據和任務該模式的核心就是數據和任務的交互點共享內存緩 前言 這篇主要來講解多線程中一個非常經典的設計模式包括它的基礎到拓展希望大家能夠有所收獲 生產者-消費者模式簡述 此設計模式中主要分兩類線程:生產者...
閱讀 1833·2021-11-25 09:43
閱讀 1335·2021-11-22 15:08
閱讀 3734·2021-11-22 09:34
閱讀 3225·2021-09-04 16:40
閱讀 3000·2021-09-04 16:40
閱讀 542·2019-08-30 15:54
閱讀 1334·2019-08-29 17:19
閱讀 1752·2019-08-28 18:13