亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

java多線程三之線程協作與通信實例

2019-11-14 21:05:51
字體:
來源:轉載
供稿:網友
java多線程三之線程協作與通信實例

多線程的難點主要就是多線程通信協作這一塊了,前面筆記二中提到了常見的同步方法,這里主要是進行實例學習了,今天總結了一下3個實例:

1、銀行存款與提款多線程實現,使用Lock鎖和條件Condition。     附加 : 用監視器進行線程間通信

2、生產者消費者實現,使用LinkedList自寫緩沖區。

3、多線程之阻塞隊列學習,用阻塞隊列快速實現生產者消費者模型。    附加:用布爾變量關閉線程

       在三種線程同步方法中,我們這里的實例用Lock鎖來實現變量同步,因為它比較靈活直觀。

       實現了變量的同步,我們還要讓多個線程之間進行“通話”,就是一個線程完成了某個條件之后,告訴其他線程我完成了這個條件,你們可以行動了。下面就是java提供的條件接口Condition定義的同步方法:

image

       很方便的是,java的Lock鎖里面提供了newConditon()方法可以,該方法返回:一個綁定了lock鎖的Condition實例,有點抽象,其實把它看作一個可以發信息的鎖就可以了,看后面的代碼,應該就能理解了。

1、銀行存款與提款多線程實現。

我們模擬ATM機器存款與提款,創建一個賬戶類Account(),該類包含同步方法

     存款方法:deposit()

     提款方法:withdraw()

     以及一個普通的查詢余額的方法getbalance().

我們創建兩個任務線程,分別調用兩個同步方法,進行模擬操作,看代碼:

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ThreadCoOperation {PRivate static Account account = new Account();   public static void main(String[] args){//創建線程池ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(new DepositTask());executor.execute(new WithdrawTask());}//存錢public static class DepositTask implements Runnable{@Overridepublic void run() {try {while(true){account.deposit((int)(Math.random()*1000)+1);Thread.sleep(1000);}} catch (InterruptedException e) {e.printStackTrace();}}}public static class WithdrawTask implements Runnable{@Overridepublic void run() {try{while(true){account.withdraw((int)(Math.random()*1000)+1);Thread.sleep(500);}} catch (InterruptedException e) {e.printStackTrace();}}}public static class Account{//一個鎖是一個Lock接口的實例   它定義了加鎖和釋放鎖的方法     ReentrantLock是為創建相互排斥的鎖的Lock的具體實現private static Lock lock = new ReentrantLock();//創建一個condition,具有發通知功能的鎖,前提是要實現了lock接口private static Condition  newDeposit = lock.newCondition();private int balance = 0;public int getBalance(){return balance;}public void withdraw(int amount){lock.lock();try {while(balance < amount){System.out.println("/t/t錢不夠,等待存錢");newDeposit.await();}balance -= amount;System.out.println("/t/t取出"+amount+"塊錢/t剩余"+getBalance());} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();}}public void deposit(int amount){lock.lock();try{balance+=amount;System.out.println("存入"+amount+"塊錢");newDeposit.signalAll();   //發信息喚醒所有的線程}finally{lock.unlock();}}}}

運行截圖C1]I1L)1D0(F)I4MCX3)4$I

分析:

      1、程序中需要注意的:創建一個condition,具有發通知功能的鎖,前提是要實現了lock接口。

      2、while(balance < amount)不能改用if判斷,用if會使得線程不安全,使用if會不會進行循環驗證,而while會,我們經??吹絯hile(true),但是不會經常看到if(true).

      3、調用了await方法后,要記得使用signalAll()或者signal()將線程喚醒,否則線程永久等待。

       最后再來分析一下這個類的結構,有3個類,兩個靜態任務類實現了Runnable接口,是線程類,而另外一個類則是普通的任務類,包含了線程類所用到的方法。我們的主類在main方法前面就實例化一個Account類,以供線程類調用該類里面的同步方法。

      這種構造方式是多線程常用到的一種構造方式吧。不難發現后面要手寫的生產者消費者模型也是這樣子構造的。這相當于是一個多線程模板。也是我們學習這個例子最重要的收獲吧。

 

 

用監視器進行線程之間的通信

       還有一點,接口Lock與Condition都是在java5之后出現的,在這之前,線程通信是通過內置的監視器(monitor)實現的。

      監視器是一個相互排斥且具有同步能力的對象,任意對象都有可能成為一個monitor。監視器是通過synchronized關鍵字來對自己加鎖(加鎖解鎖是解決線程同步最基本的思想),使用wait()方法時線程暫停并 等待條件發生,發通知則是通過notify()和notifyAll()方法。大體的模板是這樣子的:

image

不難看出await()、signal()、signally()是wait()、notify()、notifyAll()的進化形態,所以不建議使用監視器。

 

2、生產者消費者實現,使用LinkedList自寫緩沖區

         這個模型一直很經典,學操作系統的時候還學過,記得linux還用PV操作去實現它,不過這東西是跨學科的。

考慮緩存區buffer的使用者,生產者和消費者,他們都能識別緩沖區是否滿的,且兩種各只能發出一種信號:

       生產者:它能發出notEmpty()信號,即緩沖區非空信號,當它看到緩沖區滿的時候,它就調用await等待。

       消費者:它能發出notFull()信號,即緩沖區未滿的信號,當它看到緩沖區空的時候,它也調用await等待。

看代碼:

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;//生產者消費者public class ConsumerProducer {private static Buffer  buffer= new Buffer();public static void main(String[] args){ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(new ProducerTask());executor.execute(new ConsumerTask());executor.shutdown();}public static class ProducerTask implements Runnable{@Overridepublic void run() {int i=1;try {while(true){System.out.println("生產者寫入數據"+i);buffer.write(i++);Thread.sleep((int)(Math.random()*80));} }catch (InterruptedException e) {e.printStackTrace();}}}public static class ConsumerTask implements Runnable{public void run() {try {while(true){System.out.println("/t/t消費讀出數據"+buffer.read());Thread.sleep((int)(Math.random()*100));}} catch (InterruptedException e) {e.printStackTrace();}}}public static class Buffer{private static final int CAPACTIY = 4;  //緩沖區容量private java.util.LinkedList<Integer> queue = new java.util.LinkedList<Integer>();private static Lock lock = new ReentrantLock();private static Condition  notEmpty = lock.newCondition();private static Condition notFull = lock.newCondition();public void write(int value){lock.lock();try{while(queue.size()==CAPACTIY){System.out.println("緩沖區爆滿");notFull.await();}queue.offer(value);notEmpty.signalAll();  //通知所有的緩沖區未空的情況}catch(InterruptedException ex){ex.printStackTrace();}finally{lock.unlock();}}@SuppressWarnings("finally")public int read(){int value = 0;lock.lock();try{while(queue.isEmpty()){System.out.println("/t/t緩沖區是空的,等待緩沖區非空的情況");notEmpty.await();}value = queue.remove();notFull.signal();}catch(InterruptedException ex){ex.printStackTrace();}finally{lock.unlock();return value;}}}}

 

運行截圖image

程序運行正常,不過稍微延長一下讀取時間,就會出現這樣的情況image

     

        程序里面設置的容量是4,可是這里卻可以存入最多5個數據,而且更合理的情況應該是初始緩沖區是空的,后面找了下這個小bug,原來是調用offer()函數應該放在檢測語句之前,如果希望一開始就調用ConsumerTask,在main方法里面調換兩者的順序即可。

3、用阻塞隊列快速實現生產者消費者模型

        java的強大之處是它有著豐富的類庫,我們學習java在某種程度上就是學習這些類庫。

 

        阻塞隊列是這樣的一種隊列:當試圖向一個滿隊列里添加元素  或者 從空隊列里刪除元素時,隊列會讓線程自動阻塞,且當隊列滿時,隊列會繼續存儲元素,供喚醒后的線程使用。這應該說是專門為消費者生產者模型而設計的一種隊列吧,它實現了Queue接口,主要方法是put()和take()方法。

                                                                         EU7H[HB1$E{SB3MZ)@DT89B

java支持三個具體的阻塞隊列ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue。都在java.util.concurrent包中。

      

簡單描述上面三個阻塞隊列:

          ArrayBlockingQueue: 該阻塞用數組實現,按照FIFO,即先進先出的原則對數據進行排序,和數組的使用有點相似,它事先需要指定一個容量,不過即便隊列超出這個容量,也是不會報錯滴。

          LinkeddBlockingQueue:用鏈表實現,默認隊列大小是Integer.MAX_VALUE,也是按照先進先出的方法對數據排序,性能可能比ArrayBlockingQueue,有待研究。

          PriorityBlockingQueue:用優先隊列實現的阻塞隊列,會對元素按照大小進行排序,也可以創建不受限制的隊列,put方法永不阻塞。

 

ok,看代碼:

import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ConsumerProducerUsingBlockQueue {private static ArrayBlockingQueue<Integer>  buffer = new ArrayBlockingQueue<Integer>(2);public static void main(String[] args){ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(new Consumer());executor.execute(new Producer());try {Thread.sleep(100);executor.shutdownNow();     //暴力關閉,會報錯,不推薦} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static class Consumer implements Runnable{@Overridepublic void run() {try{int i=1;while(true){System.out.println("生成者寫入:"+i);buffer.put(i++);Thread.sleep((int)(Math.random())*1000);}}catch(InterruptedException ex){ex.printStackTrace();}}}public static class Producer implements Runnable{@Overridepublic void run() {try{while(true){System.out.println("/t/t消費者取出"+buffer.take());Thread.sleep((int)(Math.random())*10000);}}catch(InterruptedException ex){ex.printStackTrace();}}}}

 

運行截圖:1cd4147312c04552aded4cc98ba76a10

        沒啥大的問題,就是在關閉線程的時候太過暴力了,會報錯,線程里面的每一個函數都似乎值得研究,之前想通過Interrupt暫停,不過失敗了,就直接使用線程池執行器的shoutdownNow方法來的。后面自己又用了另外一種關閉線程的方法,見下面代碼

 

使用LinkedBlockingQueue實現消費者生產者且使用布爾變量控制線程關閉
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;public class A_Control_stop {private static LinkedBlockingQueue<String>  buffer = new LinkedBlockingQueue<String>();public static void main(String[] args){ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(new Consumer());executor.execute(new Producer());executor.shutdown();while(!executor.isTerminated()){}System.out.println("所有的的線程都正常結束");}public static class Consumer implements Runnable{private volatile boolean exit = false;@Overridepublic void run() {try{int i=0;String[] str ={"as","d","sd","ew","sdfg","esfr"};while(!exit){System.out.println("生成者寫入:"+str[i]);buffer.put(str[i++]);Thread.sleep((int)(Math.random())*10);if(5==i){exit=true;}}}catch(InterruptedException ex){ex.printStackTrace();}}}public static class Producer implements Runnable{private volatile boolean exit = false;@Overridepublic void run() {try{int i=0;while(!exit){System.out.println("/t/t消費者取出"+buffer.take());i++;Thread.sleep((int)(Math.random())*10);if(5==i){exit=true;}}}catch(InterruptedException ex){ex.printStackTrace();}}}}

 

截圖image

         關于阻塞隊列,覺得這篇文章講的不錯,推薦大家看看  聊聊并發----Java中的阻塞隊列

        用了幾天,多線程算是學了點皮毛,附注一下:這幾天文章主要是參考了《java程序語言設計進階篇第8版》,老外寫的書講的真心不錯,只不過現在java都已經更新到java8了。在其他一些網站上看到自己的文章,沒有說明轉載什么的,估計是直接“被采集”過去了。

        本文出自于博客園蘭幽,轉載請說明出處。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩亚洲一区二| 久久精品99无色码中文字幕| 在线观看欧美日韩| 中文字幕日本欧美| 欧美成人亚洲成人| 九九视频直播综合网| 亚洲精品一区二区三区不| 欧美极品第一页| 久久精品国产久精国产一老狼| 欧美精品激情视频| 亚洲第一福利在线观看| 国产成人一区二| 日韩精品视频在线播放| 国产成人精品优优av| 欧美性猛交xxxx乱大交极品| 欧美高清理论片| 欧美日韩亚洲系列| 精品五月天久久| 中国china体内裑精亚洲片| 亚洲电影成人av99爱色| 亚洲国产成人久久| 国产婷婷成人久久av免费高清| 亚洲精品mp4| 国产精品成av人在线视午夜片| 欧美日韩激情美女| 亚洲精品视频播放| 国产精品亚洲综合天堂夜夜| 91亚洲国产成人久久精品网站| 国产欧美日韩免费看aⅴ视频| 亚洲人在线视频| 欧美在线视频免费观看| 成人淫片在线看| 日韩一区在线视频| 91大神福利视频在线| 亚洲欧洲一区二区三区久久| 欧美日韩国产丝袜美女| 色yeye香蕉凹凸一区二区av| 国产精品日韩欧美大师| 国内外成人免费激情在线视频网站| 国产精品久久久久久久av电影| 精品国产福利视频| 91高清视频免费| 久久人人爽人人爽爽久久| 亚洲女人天堂色在线7777| www.亚洲天堂| 456国产精品| 欧美裸体xxxx极品少妇软件| 国产精品成人品| 国产精品午夜视频| 亚洲伊人成综合成人网| 伊是香蕉大人久久| 最新国产精品亚洲| 日韩综合中文字幕| 国产欧美一区二区三区久久| 亚洲综合在线做性| 亚洲xxxx妇黄裸体| 国产女精品视频网站免费| 欧美一性一乱一交一视频| 亚洲人成电影网站色www| 岛国精品视频在线播放| 国产亚洲精品一区二555| 国产婷婷97碰碰久久人人蜜臀| 亚洲一区二区三区久久| 国产精品电影在线观看| 亚洲人成电影网站色xx| 91av视频在线免费观看| 精品免费在线观看| 日本aⅴ大伊香蕉精品视频| 久久久久亚洲精品| 欧美在线免费视频| 国产精品香蕉在线观看| 欧美精品在线视频观看| 国产精品在线看| 精品久久久久久久久久久久久久| 久久久综合免费视频| 欧美日韩性视频| 日韩免费观看视频| 欧美激情视频在线观看| 久久天堂av综合合色| 538国产精品一区二区免费视频| 色婷婷综合成人av| 91在线高清免费观看| 亚洲自拍另类欧美丝袜| 久久99热精品| 深夜福利日韩在线看| 97碰碰碰免费色视频| 亚洲新声在线观看| 精品成人69xx.xyz| 最近中文字幕mv在线一区二区三区四区| 亚洲精品国产suv| 国产精品18久久久久久首页狼| 亚洲精品国偷自产在线99热| 在线精品视频视频中文字幕| 亚洲天堂网在线观看| 亚洲在线www| 亚洲天堂男人天堂女人天堂| 夜夜嗨av色一区二区不卡| 欧美成人在线免费视频| 亚洲第一精品夜夜躁人人躁| 精品中文视频在线| 色综合视频网站| 国产免费一区二区三区香蕉精| 91久热免费在线视频| 欧美电影免费观看大全| 国产精品视频最多的网站| 91久久在线观看| 久久影院中文字幕| 久热精品视频在线免费观看| 伊人久久免费视频| 国产精品夫妻激情| 日韩视频在线免费| 亚洲精品一区二区三区不| 亚洲乱码国产乱码精品精| 亚洲黄色在线看| 欧美激情性做爰免费视频| 国产精品黄色影片导航在线观看| 亚洲第一精品夜夜躁人人躁| 国产精品主播视频| 亚洲一区二区黄| 日韩av大片免费看| 久久久久亚洲精品成人网小说| 色综合色综合网色综合| 亚洲女人天堂av| 国产精品入口日韩视频大尺度| 青青草原成人在线视频| 国产日韩欧美中文在线播放| 91香蕉国产在线观看| 成人高h视频在线| 亚洲国产成人精品久久| 在线播放日韩专区| 主播福利视频一区| 欧美成人一二三| 国产成人亚洲综合青青| 亚洲精品国产综合区久久久久久久| www.久久久久久.com| 精品国产欧美一区二区三区成人| 亚洲性av网站| 亚洲欧洲在线免费| 亚洲电影免费观看高清完整版在线观看| 狠狠躁夜夜躁人人爽超碰91| 91国内免费在线视频| 国产精品一区二区久久久久| 欧美成人第一页| 日韩电影免费观看在线| 亚洲区在线播放| 日韩电影第一页| 最好看的2019年中文视频| 欧美日本亚洲视频| 亚洲欧美中文字幕| 亚洲成人精品久久久| 欧美裸身视频免费观看| 欧美性猛交xxxx乱大交蜜桃| 亚洲男人天堂网| 2019亚洲日韩新视频| 日本视频久久久| 91美女片黄在线观看游戏| 精品成人国产在线观看男人呻吟| 亚洲男人的天堂在线播放| 国产精品久久久av| 中文字幕日韩有码| 国产精品中文字幕久久久| 色在人av网站天堂精品| 亚洲成人av片| 欧美电影在线观看完整版|