真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中Lock鎖與生產(chǎn)者消費者問題有哪些

小編給大家分享一下Java介紹Lock鎖與生產(chǎn)者消費者問題,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

在蒙城等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、網(wǎng)站設(shè)計、外貿(mào)營銷網(wǎng)站建設(shè) 網(wǎng)站設(shè)計制作定制網(wǎng)站制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營銷,外貿(mào)網(wǎng)站建設(shè),蒙城網(wǎng)站建設(shè)費用合理。

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

  • 傳統(tǒng)Synchronized鎖

  • Lock鎖

  • Synchronized和lock鎖的區(qū)別

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

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

  • Condition實現(xiàn)精準(zhǔ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表達(dá)式()->{代碼}
        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表達(dá)式,lambda表達(dá)式詳細(xì)描述見Java基礎(chǔ)-Lambda表達(dá)式

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

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(標(biāo)準(zhǔn)鎖)。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的進(jìn)程到達(dá),3h先,那么3s等3h,實際上也不利。
非公平鎖:十分不公平,可以插隊(默認(rèn))
之后,我們會具體解釋。

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

//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表達(dá)式()->{代碼}
		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è)務(wù)代碼
			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必須要手動釋放鎖!如果不釋放鎖,會導(dǎo)致死鎖
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è)務(wù)+通知

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è)務(wù)+通知class Data{		//數(shù)字。資源類
	private int number=0;
	
	//+1。多線程的情況下一定要加鎖。
	public synchronized void increment() throws InterruptedException{
		//判斷是否需要等待,如果不需要,就需要干活進(jìn)行業(yè)務(wù)操作
		if(number!=0){			//等于1的時候,需要等待,緩沖區(qū)只有1個空位置
			//等待操作
			this.wait();
		}
		number++;		//進(jìn)行業(yè)務(wù)操作
		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)進(jìn)入了代碼的等待那一行,這時,在wait下的線程可能有多個,甚至包括生產(chǎn)者和消費者。有可能某個生產(chǎn)者執(zhí)行完了之后,喚醒的是另一個生產(chǎn)者。

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

public final void wait(long timeout)
                throws InterruptedException

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

 synchronized (obj) {
         while ()
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     }

注意點:防止虛假喚醒問題。
我們代碼中用的是if判斷,而應(yīng)該用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è)務(wù)+通知class Data{     //數(shù)字。資源類
    private int number=0;
    
    //+1
    public synchronized void increment() throws InterruptedException{
        //判斷是否需要等待,如果不需要,就需要干活進(jìn)行業(yè)務(wù)操作
        while(number!=0){           //等于1的時候,需要等待,緩沖區(qū)只有1個空位置
            //等待操作
            this.wait();
        }
        number++;       //進(jìn)行業(yè)務(wù)操作
        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實例。
在等待條件之前,鎖必須由當(dāng)前線程保持。 呼叫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è)務(wù)+通知

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è)務(wù)代碼
			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è)務(wù)代碼
			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。即精準(zhǔn)通知。

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

Condition實現(xiàn)精準(zhǔ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è)務(wù),判斷->執(zhí)行->通知
            while(number!=1){
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            //喚醒,喚醒指定的人,B
            number=2;           //精準(zhǔn)喚醒
            condition2.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }   
    public void printB(){
        lock.lock();
        try {
            //業(yè)務(wù),判斷->執(zhí)行->通知
            while(number!=2){
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");
            //喚醒,喚醒指定的人,C
            number=3;           //精準(zhǔn)喚醒
            condition3.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            //業(yè)務(wù),判斷->執(zhí)行->通知
            while(number!=3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");
            //喚醒,喚醒指定的人,A
            number=1;           //精準(zhǔn)喚醒
            condition1.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }}

以上是“Java介紹Lock鎖與生產(chǎn)者消費者問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


分享標(biāo)題:Java中Lock鎖與生產(chǎn)者消費者問題有哪些
文章地址:http://weahome.cn/article/jhside.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部