久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      Java介紹Lock鎖與生產(chǎn)者消費者問題

      Java介紹Lock鎖與生產(chǎn)者消費者問題

      免費學習推薦:java基礎(chǔ)教程

      Lock鎖與生產(chǎn)者消費者問題

      • 傳統(tǒng)Synchronized鎖
      • Lock鎖
      • Synchronized和lock鎖的區(qū)別
      • 傳統(tǒng)的生產(chǎn)者和消費者問題
      • Lock版的生產(chǎn)者和消費者問題
      • Condition實現(xiàn)精準通知喚醒

      傳統(tǒng)Synchronized鎖

      實現(xiàn)一個基本的售票例子:

      /* 真正的多線程開發(fā),公司中的開發(fā),降低耦合性 線程就是一個單獨的資源類,沒有任何附屬的操作 1.屬性,方法  * */public class SaleTicketDemo1 {     public static void main(String[] args) {         //并發(fā),多個線程操作同一個資源類,把資源類丟入線程         Ticket ticket=new Ticket();         //Runnable借口是一個FunationalInterface函數(shù)式接口,接口可以new,jdk1.8以后,lamda表達式()->{代碼}         new Thread(()->{             for(int i=0;i<60;i++){                 ticket.sale();             }         },"A").start();         new Thread(new Runnable() {             @Override             public void run() {                 for(int i=0;i<60;i++){                     ticket.sale();                 }             }         },"B").start();         new Thread(()->{             for(int i=0;i<60;i++){                 ticket.sale();             }         },"C").start();     }}//資源類 OOPclass Ticket{     //屬性,方法     private int number=50;     //賣票的方式     //synchronized本質(zhì):隊列,所     public synchronized void sale(){         if(number>0){             System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩余"+number);         }     }}

      注意,這里面用到了lambda表達式,lambda表達式詳細描述見Java基礎(chǔ)-Lambda表達式

      Java介紹Lock鎖與生產(chǎn)者消費者問題
      這是使用傳統(tǒng)的synchronized實現(xiàn)并發(fā),synchronized的本質(zhì)就是隊列,鎖。就好比食堂排隊。如果沒有排隊,就會很亂。只有給一個人服務完成了,另一個人才能接收到服務。

      Lock鎖

      之前已經(jīng)說道,JVM提供了synchronized關(guān)鍵字來實現(xiàn)對變量的同步訪問以及用wait和notify來實現(xiàn)線程間通信。在jdk1.5以后,JAVA提供了Lock類來實現(xiàn)和synchronized一樣的功能,并且還提供了Condition來顯示線程間通信。
      Lock類是Java類來提供的功能,豐富的api使得Lock類的同步功能比synchronized的同步更強大。
      在java.util. Concurrent包中,里面有3個接口,Condition,lock(標準鎖)。ReadWriteLock鎖(讀寫鎖)
      Lock實現(xiàn)提供比使用synchronized方法和語句可以獲得的更廣泛的鎖定操作。 它們允許更靈活的結(jié)構(gòu)化,可能具有完全不同的屬性,并且可以支持多個相關(guān)聯(lián)的對象Condition。

      Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }

      lock()表示加鎖,unlock()表示解鎖
      JDK官方文檔中解釋
      Java介紹Lock鎖與生產(chǎn)者消費者問題
      所有已知實現(xiàn)類:
      ReentrantLock可重入鎖
      ReentrantReadWriteLock.ReadLock 讀鎖
      ReentrantReadWriteLock.writeLock寫鎖

      先說ReentrantLock實現(xiàn)類:
      ReentrantLock底層源碼構(gòu)造函數(shù)
      Java介紹Lock鎖與生產(chǎn)者消費者問題
      公平鎖:十分公平,可以先來后到。但是問題如果一個3s和一個3h的進程到達,3h先,那么3s等3h,實際上也不利。
      非公平鎖:十分不公平,可以插隊(默認)
      之后,我們會具體解釋。

      怎么用,用之前加鎖,用之后解鎖

      //lock鎖三部曲
      //1.new ReentranLock();構(gòu)造
      //2.Lock.lock();加鎖
      //3.finally();解鎖

      public class SaleTicketDemo2 { 	public static void main(String[] args) { 		//并發(fā),多個線程操作同一個資源類,把資源類丟入線程 		Ticket ticket=new Ticket(); 		//Runnable借口是一個FunationalInterface函數(shù)式接口,接口可以new,jdk1.8以后,lamda表達式()->{代碼} 		new Thread(()->{for(int i=0;i<60;i++)ticket.sale();},"A").start(); 		new Thread(()->{for(int i=0;i<60;i++)ticket.sale();},"B").start(); 		new Thread(()->{for(int i=0;i<60;i++)ticket.sale();},"C").start(); 	}}//資源類 OOP//lock鎖三部曲//1.new ReentranLock();//2.Lock.lock();加鎖//3.finally();解鎖class Ticket2{ 	//屬性,方法 	private int number=50; 	//賣票的方式 	//synchronized本質(zhì):隊列,所 	Lock lock=new ReentrantLock(); 	 	public void sale(){ 		lock.lock(); 		try { 			//業(yè)務代碼 			if(number>0){ 				System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩余"+number); 			} 		} catch (Exception e) { 			// TODO: handle exception 		}finally{ 			lock.unlock(); 		}	 	}}

      Synchronized和lock鎖的區(qū)別

      1.synchronized是內(nèi)置的java關(guān)鍵字,lock是一個Java類
      2.synchronized無法判斷獲取鎖的狀態(tài),lock可以判斷是否獲取到了鎖
      3.synchronized會自動釋放鎖(a–),lock必須要手動釋放鎖!如果不釋放鎖,會導致死鎖
      4.Synchronized線程1(獲得鎖,阻塞),線程2(等待,傻傻的等)
      lock.tryLock()嘗試獲取鎖,不一定會一直等待下去
      5.Synchronized可重入鎖,不可以中斷的,非公平鎖。Lock,可重入鎖,可以判斷鎖,公平與非公平可以自己設(shè)置(可以自己設(shè)置)
      6.synchronized適合少量的代碼同步問題,lock鎖適合鎖大量的同步代碼
      synchornized鎖對象和同步代碼塊方法

      傳統(tǒng)的生產(chǎn)者和消費者問題

      傳統(tǒng)的生產(chǎn)者和消費者是基于Object類的wait、notify方法和synchronized關(guān)鍵字來實現(xiàn)的。
      在面試的時候,手寫生產(chǎn)者消費者代碼是很常見的事情。
      面試筆試經(jīng)典問題:
      單例模式+排序算法+生產(chǎn)者消費者+死鎖
      生產(chǎn)者消費者問題synchronized版

      線程之間的通信問題:生產(chǎn)者和消費者問題 等待喚醒,通知喚醒
      線程交替執(zhí)行 A B 操作同一個變量number=0
      A num+1
      B num-1

      注意:加鎖的方法中,執(zhí)行的思路是判斷等待+業(yè)務+通知

      package testConcurrent;/* 線程之間的通信問題:生產(chǎn)者和消費者問題    等待喚醒,通知喚醒 線程交替執(zhí)行 A B 操作同一個變量number=0 A num+1 B num-1   * */public class A { 	public static void main(String[] args) { 		Data data =new Data(); 		new Thread(()->{ 			for(int i=0;i<10;i++){ 				try { 					data.increment(); 				} catch (Exception e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 			} 		},"A").start(); 		new Thread(()->{ 			for(int i=0;i<10;i++){ 				try { 					data.decrement(); 				} catch (Exception e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 			} 		},"B").start();	 	}}//判斷等待+業(yè)務+通知class Data{		//數(shù)字。資源類 	private int number=0; 	 	//+1。多線程的情況下一定要加鎖。 	public synchronized void increment() throws InterruptedException{ 		//判斷是否需要等待,如果不需要,就需要干活進行業(yè)務操作 		if(number!=0){			//等于1的時候,需要等待,緩沖區(qū)只有1個空位置 			//等待操作 			this.wait(); 		} 		number++;		//進行業(yè)務操作 		System.out.println(Thread.currentThread().getName()+"=>"+number); 		//通知其他線程,我+1完畢了 		this.notify(); 	} 	//-1 	public synchronized void decrement() throws InterruptedException{ 		if(number==0){ 			//等待 			this.wait(); 		} 		number--; 		System.out.println(Thread.currentThread().getName()+"=>"+number); 		//通知其他線程,我-1完畢了 		this.notify(); 	}}

      Java介紹Lock鎖與生產(chǎn)者消費者問題
      如圖,基本可以實現(xiàn)所要求的功能,但是這樣還會出現(xiàn)問題,如果此時我再加上了兩個線程,則

      		new Thread(()->{ 			for(int i=0;i<10;i++){ 				try { 					data.increment(); 				} catch (Exception e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 			} 		},"C").start(); 		new Thread(()->{ 			for(int i=0;i<10;i++){ 				try { 					data.decrement(); 				} catch (Exception e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 			} 		},"D").start();

      Java介紹Lock鎖與生產(chǎn)者消費者問題
      這里結(jié)果中出現(xiàn)了2,輸出結(jié)果出現(xiàn)了問題。為什么呢?
      為什么if判斷會出現(xiàn)問題:
      if判斷只判斷一次。因為if判斷了之后,就已經(jīng)進入了代碼的等待那一行,這時,在wait下的線程可能有多個,甚至包括生產(chǎn)者和消費者。有可能某個生產(chǎn)者執(zhí)行完了之后,喚醒的是另一個生產(chǎn)者。

      在我們的官方文檔中就給出了解釋

      public final void wait(long timeout)                 throws InterruptedException

      導致當前線程等待,直到另一個線程調(diào)用此對象的notify()方法或notifyAll()方法,或指定的時間已過。
      線程也可以喚醒,而不會被通知,中斷或超時,即所謂的虛假喚醒 。 雖然這在實踐中很少會發(fā)生,但應用程序必須通過測試應該使線程被喚醒的條件來防范,并且如果條件不滿足則繼續(xù)等待。 換句話說,等待應該總是出現(xiàn)在循環(huán)中,就像這樣:

       synchronized (obj) {          while (<condition does not hold>)              obj.wait(timeout);          ... // Perform action appropriate to condition      }

      注意點:防止虛假喚醒問題
      我們代碼中用的是if判斷,而應該用while判斷

      package testConcurrent;/* 線程之間的通信問題:生產(chǎn)者和消費者問題    等待喚醒,通知喚醒 線程交替執(zhí)行 A B 操作同一個變量number=0 A num+1 B num-1   * */public class A {     public static void main(String[] args) {         Data data =new Data();         new Thread(()->{             for(int i=0;i<10;i++){                 try {                     data.increment();                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }         },"A").start();         new Thread(()->{             for(int i=0;i<10;i++){                 try {                     data.decrement();                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }         },"B").start();         new Thread(()->{             for(int i=0;i<10;i++){                 try {                     data.increment();                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }         },"C").start();         new Thread(()->{             for(int i=0;i<10;i++){                 try {                     data.decrement();                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }         },"D").start();              }}//判斷等待+業(yè)務+通知class Data{     //數(shù)字。資源類     private int number=0;          //+1     public synchronized void increment() throws InterruptedException{         //判斷是否需要等待,如果不需要,就需要干活進行業(yè)務操作         while(number!=0){           //等于1的時候,需要等待,緩沖區(qū)只有1個空位置             //等待操作             this.wait();         }         number++;       //進行業(yè)務操作         System.out.println(Thread.currentThread().getName()+"=>"+number);         //通知其他線程,我+1完畢了         this.notify();     }     //-1     public synchronized void decrement() throws InterruptedException{         while(number==0){             //等待             this.wait();         }         number--;         System.out.println(Thread.currentThread().getName()+"=>"+number);         //通知其他線程,我-1完畢了         this.notify();     }}

      Lock版的生產(chǎn)者和消費者問題

      在synchronized版本中,我們使用了wait和notify來實現(xiàn)線程之間的同步
      在lock中,
      此時synchronized被lock替換了,那么wait和notify用什么來替換呢?
      我們在官方文檔java.util.concurrent.locks 中,找到Lock類,然后在底部找到了
      Condition newCondition()
      返回一個新Condition綁定到該實例Lock實例。
      在等待條件之前,鎖必須由當前線程保持。 呼叫Condition.await()將在等待之前將原子釋放鎖,并在等待返回之前重新獲取鎖。

      然后我們再來了解Condition類
      Condition 將 Object 監(jiān)視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現(xiàn)組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監(jiān)視器方法的使用。
      一個Condition實例本質(zhì)上綁定到一個鎖。 要獲得特定Condition實例的Condition實例,請使用其newCondition()方法。

      Java介紹Lock鎖與生產(chǎn)者消費者問題
      我們可以看到,使用的時候new一個Condition對象。然后用await替代wait,signal替換notify
      代碼實現(xiàn)
      //判斷等待+業(yè)務+通知

      class Data2{		//數(shù)字。資源類 	private int number=0; 	Lock lock=new ReentrantLock(); 	Condition condition=lock.newCondition(); 	//+1 	public void increment() throws InterruptedException{ 		try { 			lock.lock(); 			//業(yè)務代碼 			while(number!=0){		 				//等待 				condition.await(); 			} 			number++;		 			System.out.println(Thread.currentThread().getName()+"=>"+number); 			condition.signalAll();		//通知 		} catch (Exception e) { 			// TODO: handle exception 		}finally{ 			lock.unlock(); 		} 	} 	//-1 	public void decrement() throws InterruptedException{ 		try { 			lock.lock(); 			//業(yè)務代碼 			while(number!=1){		 				//等待 				condition.await(); 			} 			number--;		 			System.out.println(Thread.currentThread().getName()+"=>"+number); 			condition.signalAll();		//通知 		} catch (Exception e) { 			// TODO: handle exception 		}finally{ 			lock.unlock(); 		} 	}	}

      注意:主函數(shù)部分于最上面的代碼一樣。

      Java介紹Lock鎖與生產(chǎn)者消費者問題
      這時候雖然說是正確的,但是它是一個隨機分布的狀態(tài),現(xiàn)在我們希望它有序執(zhí)行,即A執(zhí)行完了執(zhí)行B,B執(zhí)行C,C完了執(zhí)行D。即精準通知。

      Condition實現(xiàn)精準通知喚醒

      Condition實現(xiàn)精準的通知和喚醒
      我們構(gòu)造三個線程,要求A執(zhí)行完了執(zhí)行B,B執(zhí)行完了執(zhí)行C,C執(zhí)行完了執(zhí)行D.
      代碼思想:
      //加多個監(jiān)視器,通過監(jiān)視器來判斷喚醒的是哪一個人
      //設(shè)置多個同步監(jiān)視器,每個監(jiān)視器監(jiān)視一個線程
      //實例:生產(chǎn)線,下單->支付->交易->物流

      package testConcurrent;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/* A執(zhí)行完調(diào)用B,B執(zhí)行完調(diào)用C,C執(zhí)行完調(diào)用A  * */public class C {      public static void main(String[] args) {         Data3 data=new Data3();         new Thread(()->{             for(int i=0;i<10;i++){                 data.printA();             }         },"A").start();         new Thread(()->{             for(int i=0;i<10;i++){                 data.printB();             }         },"B").start();         new Thread(()->{             for(int i=0;i<10;i++){                 data.printC();             }         },"C").start();     }}class Data3{    //資源類     private Lock lock=new ReentrantLock();     //加多個監(jiān)視器,通過監(jiān)視器來判斷喚醒的是哪一個人     //設(shè)置多個同步監(jiān)視器,每個監(jiān)視器監(jiān)視一個線程     //實例:生產(chǎn)線,下單->支付->交易->物流     private Condition condition1=lock.newCondition();     private Condition condition2=lock.newCondition();     private Condition condition3=lock.newCondition();     private int number=1;       //1A 2B 3C     public void printA(){         lock.lock();         try {             //業(yè)務,判斷->執(zhí)行->通知             while(number!=1){                 //等待                 condition1.await();             }             System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");             //喚醒,喚醒指定的人,B             number=2;           //精準喚醒             condition2.signal();                      } catch (Exception e) {             // TODO: handle exception         }finally{             lock.unlock();         }     }        public void printB(){         lock.lock();         try {             //業(yè)務,判斷->執(zhí)行->通知             while(number!=2){                 //等待                 condition2.await();             }             System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");             //喚醒,喚醒指定的人,C             number=3;           //精準喚醒             condition3.signal();                      } catch (Exception e) {             // TODO: handle exception         }finally{             lock.unlock();         }     }     public void printC(){         lock.lock();         try {             //業(yè)務,判斷->執(zhí)行->通知             while(number!=3){                 //等待                 condition3.await();             }             System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");             //喚醒,喚醒指定的人,A             number=1;           //精準喚醒             condition1.signal();                      } catch (Exception e) {             // TODO: handle exception         }finally{             lock.unlock();         }     }}

      相關(guān)學習推薦:java基礎(chǔ)

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號