摘要:共享鎖能被多個(gè)線程同時(shí)擁有,能被共享的鎖。需要和聯(lián)合使用,它的作用是代替監(jiān)視器方法,可以通過來休眠喚醒線程。生產(chǎn)者消費(fèi)產(chǎn)品新建一個(gè)線程向倉庫中生產(chǎn)產(chǎn)品。
AQS
AbstractQueuedSynchronizer 抽象類
AQS 是 java 中管理 “鎖” 的抽象類,鎖的許多公共方法都是在這個(gè)類中實(shí)現(xiàn)。
AQS 是獨(dú)占鎖 (例如,ReentrantLock) 和共享鎖 (例如,Semaphore) 的公共父類。
1.1 獨(dú)占鎖
鎖在一個(gè)時(shí)間點(diǎn)只能被一個(gè)線程鎖占有。根據(jù)鎖的獲取機(jī)制,它又劃分為 “ 公平鎖 ” 和 “ 非公平鎖 ”。
1.1.1 公平鎖,是按照通過 CLH 等待線程按照先來先得的規(guī)則,公平的獲取鎖;
1.1.2 非公平鎖,則當(dāng)線程要獲取鎖時(shí),它會(huì)無視 CLH 等待隊(duì)列而直接獲取鎖。獨(dú)占鎖的典型實(shí)例子是 ReentrantLock,此外,ReentrantReadWriteLock.WriteLock 也是獨(dú)占鎖。
1.2 共享鎖
能被多個(gè)線程同時(shí)擁有,能被共享的鎖。JUC 包中的 ReentrantReadWriteLock.ReadLock,CyclicBarrier, CountDownLatch 和 Semaphore 都是共享鎖。這些鎖的用途和原理,在以后的章節(jié)再詳細(xì)介紹。
![圖片上傳中...]
ReentrantLock如果采用Lock,必須主動(dòng)去釋放鎖;但是發(fā)生異常時(shí),不會(huì)自動(dòng)釋放鎖。
因此一般來說,使用Lock必須在try{}catch{}中進(jìn)行,并且將釋放鎖的操作放在finally塊中進(jìn)行,以保證鎖一定會(huì)被釋放,防止死鎖。
使用Lock 進(jìn)行同步的話,形式如下:
Lock lock = ...; lock.lock(); // 加鎖 try{ // 處理任務(wù) }catch(Exception ex){ }finally{ lock.unlock(); // 釋放鎖 }
多線程對(duì)共享資源進(jìn)行操作的時(shí)候,使用鎖是十分必要的
假設(shè)有一個(gè)生產(chǎn)者類mPro,一個(gè)消費(fèi)者類mCus,每次操作創(chuàng)建一個(gè)線程。
mPro.produce(60); mPro.produce(120); mCus.consume(90); mCus.consume(150); mPro.produce(110);
如果不使用獨(dú)占鎖,很可能出現(xiàn)
Thread-0 produce(60) --> size=-60
Thread-4 produce(110) --> size=50
Thread-2 consume(90) <-- size=-60
Thread-1 produce(120) --> size=-60
Thread-3 consume(150) <-- size=-60
因?yàn)槭紫染€程1 對(duì)size +60, 沒有調(diào)用println的時(shí)候,切換到線程2, 又加了120, 沒打印又被切換了,然后連續(xù)兩次消費(fèi)了90 和 150再切換到線程1打印,這個(gè)時(shí)候size就是-60了。
Condition 接口描述了可能會(huì)與鎖有關(guān)聯(lián)的條件變量。Condition 需要和 Lock 聯(lián)合使用,它的作用是代替 Object 監(jiān)視器方法,可以通過 await(),signal() 來休眠 / 喚醒線程。
比如生產(chǎn)者-消費(fèi)者問題中,共享資源空的時(shí)候,消費(fèi)者不能再消費(fèi);共享資源滿的時(shí)候,生產(chǎn)者不能再生產(chǎn);所以Lock 需要借助Condition
private Condition fullCondtion; // 生產(chǎn)條件 private Condition emptyCondtion; // 消費(fèi)條件
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; class Depot{ private int capacity; // 倉庫的容量 private int size; // 倉庫的實(shí)際數(shù)量 private Lock lock; //獨(dú)占鎖 private Condition fullCondition; // 生產(chǎn)條件 private Condition emptyCondition; // 消費(fèi)條件 public Depot(int capacity) { this.capacity = capacity; this.size = 0; this.lock = new ReentrantLock(); this.fullCondition = lock.newCondition(); this.emptyCondition = lock.newCondition(); } public void produce(int val){ lock.lock(); try{ // left 表示“想要生產(chǎn)的數(shù)量”(有可能生產(chǎn)量太多,需多此生產(chǎn)) int left = val; while(left>0){ // 庫存已滿時(shí),等待“消費(fèi)者”消費(fèi)產(chǎn)品。 while(size>=capacity) { fullCondition.await(); } // 獲取“實(shí)際生產(chǎn)的數(shù)量”(即庫存中新增的數(shù)量) // 如果“庫存”+“想要生產(chǎn)的數(shù)量”>“總的容量”,則“實(shí)際增量”=“總的容量”-“當(dāng)前容量”。(此時(shí)填滿倉庫) // 否則“實(shí)際增量”=“想要生產(chǎn)的數(shù)量” int inc = (size+left)>capacity ? (capacity-size) : left; size += inc; left -= inc; System.out.println(Thread.currentThread().getName()+"want to produce" + val + "val-inc"+left + "actually produce "+ inc+ "now size"+size); // 通知“消費(fèi)者”可以消費(fèi)了。 emptyCondition.signal(); } } catch(InterruptedException e) { }finally { lock.unlock(); } } public void consume(int val){ lock.lock(); try{ // left 表示“客戶要消費(fèi)數(shù)量”(有可能消費(fèi)量太大,庫存不夠,需多此消費(fèi)) int left = val; while (left > 0) { // 庫存為0時(shí),等待“生產(chǎn)者”生產(chǎn)產(chǎn)品。 while (size <= 0) { emptyCondition.await(); } // 獲取“實(shí)際消費(fèi)的數(shù)量”(即庫存中實(shí)際減少的數(shù)量) // 如果“庫存”<“客戶要消費(fèi)的數(shù)量”,則“實(shí)際消費(fèi)量”=“庫存”; // 否則,“實(shí)際消費(fèi)量”=“客戶要消費(fèi)的數(shù)量”。 int dec = (size
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64330.html
摘要:一簡介多線程環(huán)境下,我們經(jīng)常需要多個(gè)線程的并發(fā)和協(xié)作。這個(gè)時(shí)候,就需要了解一個(gè)重要的多線程并發(fā)協(xié)作模型生產(chǎn)者消費(fèi)者模式。對(duì)于生產(chǎn)者沒有生產(chǎn)產(chǎn)品之前,消費(fèi)者要進(jìn)入等待狀態(tài)。分析不足在生產(chǎn)者消費(fèi)者問題中,僅有是不夠的。 一、簡介 多線程環(huán)境下,我們經(jīng)常需要多個(gè)線程的并發(fā)和協(xié)作。 這個(gè)時(shí)候,就需要了解一個(gè)重要的多線程并發(fā)協(xié)作模型 生產(chǎn)者 / 消費(fèi)者模式 。 模式簡圖 showImg(h...
摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準(zhǔn)備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個(gè)重要的特點(diǎn)就是內(nèi)置了對(duì)并發(fā)的支持,讓Java大受企業(yè)和程序員...
摘要:如何使用優(yōu)化高并發(fā)場景寫庫或者耗時(shí)計(jì)算在的接口中使用消息隊(duì)列,把要入庫的數(shù)據(jù)寫入的類型中。高容錯(cuò)子進(jìn)程異常奔潰時(shí),主進(jìn)程將重建子進(jìn)程。高性能多進(jìn)程運(yùn)行,充分利用多個(gè)并行計(jì)算,性能強(qiáng)勁。 經(jīng)常在群里聽到一些朋友問:TP 的項(xiàng)目怎么遷移到 mixphp 來處理高并發(fā),我通常都是回復(fù)需要重寫,可是一個(gè)開發(fā)很久的 TP 項(xiàng)目,代碼量巨大,又怎么可能會(huì)花大量時(shí)間成本來重寫呢? 那么為何我們不嘗試...
摘要:生產(chǎn)者消費(fèi)者問題是一個(gè)典型的多進(jìn)程同步問題。生產(chǎn)者線程開始產(chǎn)生新的元素并將它們存儲(chǔ)在緩沖區(qū)。否則,生產(chǎn)者線程將會(huì)在緩沖區(qū)創(chuàng)建一個(gè)新元素然后通知消費(fèi)者。我們建立一個(gè)線程池,它將收到兩個(gè)任務(wù),生產(chǎn)者和消費(fèi)者的任務(wù)。 原文鏈接:https://dzone.com/articles/th... 作者:Ioan Tinca 譯者:liumapp 想要了解更多關(guān)于Java生產(chǎn)者消費(fèi)者問題的演變嗎?...
閱讀 1674·2023-04-25 20:36
閱讀 2098·2021-09-02 15:11
閱讀 1227·2021-08-27 13:13
閱讀 2678·2019-08-30 15:52
閱讀 5018·2019-08-29 17:13
閱讀 1025·2019-08-29 11:09
閱讀 1515·2019-08-26 11:51
閱讀 866·2019-08-26 10:56