并發(fā)包下的重入鎖(ReentrantLock)

重入鎖可以完全替代synchronized關(guān)鍵字吹散。在JDK5.0的早期版本中,重入鎖的性能完全好于synchronized申窘。但是JDK6.0對synchronized做了大量的優(yōu)化迅箩,使得兩者差距并不大了,但是?ReentrantLock 靈活性要遠(yuǎn)高于synchronized屋摇。

1.為什么叫重入鎖揩魂?

答:從名稱上看,翻譯挺貼切的, re-entrant-lock 重-入-鎖炮温。之所以這么叫是因?yàn)檫@種鎖是可以反復(fù)進(jìn)入的火脉。當(dāng)然,僅僅局限于一個(gè)線程是可以反復(fù)的柒啤。

lock.lock();

lock.lock();

try {

i++;

}catch (Exception e) {

lock.unlock();

lock.unlock();

}

一個(gè)線程可以連續(xù)兩次獲得同一把鎖倦挂。釋放鎖也要多釋放一次。

2.中斷響應(yīng)

對于synchronized來說担巩,如果一個(gè)線程在等待鎖方援,那么只有與兩種結(jié)果,第一涛癌,得到鎖犯戏,第二 繼續(xù)等待。而使用重入鎖拳话,則提供另外一種可能先匪,那就是線程可以被中斷。也就是程序可以選擇性的取消對鎖的請求弃衍,在有些時(shí)候還是有必要的呀非。

舉個(gè)例子:如果你約好了和朋友一起去玩,結(jié)果等了1個(gè)小時(shí),你朋友給你打電話說有突發(fā)情況不能去了岸裙。那么你一定掃興的打道回府了猖败。中斷就類似于這么一套機(jī)制。如果一個(gè)線程正在等待鎖降允,那么它依然可以收到一個(gè)通知恩闻,被告知無須再等待,可以停止工作了拟糕。這種情況對處理死鎖是有一定幫助的判呕。

下面的代碼產(chǎn)生了一個(gè)死鎖,我們通過重入鎖的中斷送滞,可以有效地解決這個(gè)問題侠草。

package com.example.test;

import java.util.concurrent.locks.ReentrantLock;

/**

* Created by sql_j on 2018/3/18.

*/

public class IntLockimplements Runnable {

public static ReentrantLocklock1 =new ReentrantLock();

public static ReentrantLocklock2 =new ReentrantLock();

int lock;

public IntLock(int lock){

this.lock = lock;

}

@Override

? ? public void run() {

try {

if(lock==1){

lock1.lockInterruptibly();

try {

Thread.sleep(1000);

}catch (InterruptedException e) {

e.printStackTrace();

}

lock2.lockInterruptibly();

System.out.println("我是線程1");

}else{

lock2.lockInterruptibly();

try {

Thread.sleep(1000);

}catch (InterruptedException e) {

e.printStackTrace();

}

lock1.lockInterruptibly();

System.out.println("我是線程2");

}

}catch (Exception e) {

e.printStackTrace();

}finally {

if(lock1.isHeldByCurrentThread()){

lock1.unlock();

}

if(lock2.isHeldByCurrentThread()){

lock2.unlock();

}

}

}

public static void main(String[] args){

IntLock intLock1 =new IntLock(1);

IntLock intLock2 =new IntLock(2);

Thread thread1 =new Thread(intLock1);

Thread thread2 =new Thread(intLock2);

thread1.start();

thread2.start();

try {

Thread.sleep(1000);

}catch (InterruptedException e) {

e.printStackTrace();

}

thread1.interrupt();

}

}

線程thread1和線程thread2啟動(dòng)后, thread1先占用lock1 再占用lock2犁嗅;thread2先占用lock2 再占用lock1边涕,很容易形成 兩個(gè)線程相互等待。這里用lickInterruptibly()方法褂微。這個(gè)方法可以在等待鎖的過程中功蜓,響應(yīng)中斷。




3.trylock()

我們可以用trylock()方法進(jìn)行限時(shí)等待宠蚂。



public class IntLockimplements Runnable {

public static ReentrantLocklock1 =new ReentrantLock();

@Override

? ? public void run() {

try {

try {

if(lock1.tryLock(3, TimeUnit.SECONDS)){

Thread.sleep(6000);

}else{

System.out.println("get lock feild");

}

}catch (InterruptedException e) {

e.printStackTrace();

}

}catch (Exception e) {

e.printStackTrace();

}finally {

if(lock1.isHeldByCurrentThread()){

lock1.unlock();

}

}

}

}


我們同樣開啟兩個(gè)線程式撼,這時(shí)候 trylock(),會(huì)在3S內(nèi)試著去請求鎖求厕,請求不到 就會(huì)返回false著隆。


ReentrantLock.tryLock();方法也可以不帶參數(shù)直接運(yùn)行。



3.公平鎖

我們在平時(shí)的應(yīng)用中就知道呀癣,在大多數(shù)情況下美浦,鎖的申請是非公平的,無序的项栏。這就好比浦辨,買票不要排隊(duì),誰能擠到最前面沼沈,誰就先買到票流酬。而公平鎖,是按照時(shí)間順序來排隊(duì)的列另,它不會(huì)產(chǎn)生饑餓現(xiàn)象康吵,只要你排隊(duì),就一定能得到資源访递。如果我們使用synchronized關(guān)鍵字進(jìn)行鎖的控制,那它就是非公平的同辣。


示例:


public static ReentrantLock fireLock = new ReentrantLock(true);

? ? @Override

? ? public void run() {

? ? ? ? try {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? if(fireLock.tryLock(3, TimeUnit.SECONDS)){

? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? System.out.println("get lock feild");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? if(fireLock.isHeldByCurrentThread()){

? ? ? ? ? ? ? ? fireLock.unlock();

? ? ? ? ? ? }

? ? ? ? }

? ? }




4.重入鎖的好搭檔:Condition條件

Condition和 Object.wait()拷姿、Obejct.notify() 方法的作用是大致相同的惭载。只不過,Condition是作用在ReentrantLock上响巢,而Object.wait()描滔、Obejct.notify() 是作用在 synchronized上的。

await():方法會(huì)使當(dāng)前線程等待踪古,同時(shí)釋放當(dāng)前鎖含长,其它線程中使用signal()或signalAll()方法時(shí),線程會(huì)重新獲得鎖伏穆,并繼續(xù)執(zhí)行拘泞。或者當(dāng)線程被中斷時(shí)枕扫,也能跳出等待陪腌。

awaitUninteerrupibly():和await()方法類似,但是不會(huì)在等待響應(yīng)過程中被中斷烟瞧。

signal():用于喚醒一個(gè)在等待中的線程诗鸭。

signalAll():用于喚醒所有在等待的線程。

示例:

package com.example.test;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

/**

* Created by sql_j on 2018/3/18.

*/

public class IntLockimplements Runnable {

private static ReentrantLocklock =new ReentrantLock(true);

private static Conditioncondition =lock.newCondition();

@Override

? ? public void run() {

try {

lock.lock();

condition.await();

System.out.println("執(zhí)行");

}catch (InterruptedException e) {

e.printStackTrace();

}finally {

if(lock.isHeldByCurrentThread()){

lock.unlock();

}

}

}

public static void main(String[] args){

IntLock intLock =new IntLock();

Thread thread =new Thread(intLock);

thread.start();

try {

Thread.sleep(3000);

}catch (InterruptedException e) {

e.printStackTrace();

}

lock.lock();

condition.signal();

lock.unlock();

}

}


5.對于ReentrantLock的應(yīng)用整理如下

? ? lock():獲得鎖参滴,如果鎖被占用强岸,則等待。

? ? lockInterruptibly():獲得鎖砾赔,但優(yōu)先響應(yīng)中斷蝌箍。

? ? tryLock():嘗試獲得鎖,如果成功过蹂,返回true十绑,失敗返回false。該方法不等待酷勺,立即返回本橙。

? ? tryLock(long time,TimeUnit unit):在給定時(shí)間內(nèi)嘗試獲得鎖。

? ? unlock():釋放鎖脆诉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甚亭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子击胜,更是在濱河造成了極大的恐慌亏狰,老刑警劉巖候生,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刊棕,死亡現(xiàn)場離奇詭異括堤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柿估,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钉蒲,“玉大人浓利,你說我怎么就攤上這事」还遥” “怎么了旁仿?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孽糖。 經(jīng)常有香客問我枯冈,道長,這世上最難降的妖魔是什么办悟? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任尘奏,我火速辦了婚禮,結(jié)果婚禮上誉尖,老公的妹妹穿的比我還像新娘罪既。我一直安慰自己,他們只是感情好铡恕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布琢感。 她就那樣靜靜地躺著,像睡著了一般探熔。 火紅的嫁衣襯著肌膚如雪驹针。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天诀艰,我揣著相機(jī)與錄音柬甥,去河邊找鬼。 笑死其垄,一個(gè)胖子當(dāng)著我的面吹牛苛蒲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绿满,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼臂外,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了喇颁?” 一聲冷哼從身側(cè)響起漏健,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎橘霎,沒想到半個(gè)月后蔫浆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姐叁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年瓦盛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洗显。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谭溉,死狀恐怖墙懂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扮念,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布碧库,位于F島的核電站柜与,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嵌灰。R本人自食惡果不足惜弄匕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沽瞭。 院中可真熱鬧迁匠,春花似錦、人聲如沸驹溃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豌鹤。三九已至亡哄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間布疙,已是汗流浹背蚊惯。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灵临,地道東北人截型。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像儒溉,于是被迫代替她去往敵國和親宦焦。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容