七:重入鎖(鎖中斷,等待限時)

重入鎖可以替代synchronized關(guān)鍵字,在JDK 5.0的以前版本中,重入鎖的性能遠遠好于synchronized ,從6.0開始,JDK在synchronized上做了大量優(yōu)化,使兩者的性能差別并不大.

public class ReenterLock implements Runnable{
    public static ReentrantLock lock = new ReentrantLock();
    public static int i = 0;
    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            lock.lock();
            try {
                i++;
            }finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        ReenterLock rt = new ReenterLock();
        Thread t1 = new Thread(rt);
        Thread t2 = new Thread(rt);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

從代碼中可以看出,重入鎖可以顯示的對代碼塊進行加鎖,釋放鎖,這樣會比synchronized更加靈活,但是需要注意得是,用ReentrantLock 必須手動釋放鎖.

重入鎖的意義: 同一個線程可以兩次獲取同一把鎖,如果不是重入鎖,會產(chǎn)生死鎖的情況.
在以下程序中丘逸,子類改寫了父類的 synchronized 方法挪凑,然后調(diào)用父類中的方法鞭呕,此時如果內(nèi)置鎖不是可重入的乍丈,等待一個永遠等不到的鎖,那么這段代碼將產(chǎn)生死鎖.

public class Widget{
    public synchronized void doSomething(){
        ........
    }
}

public class LoggingWidget extends Widget{
    public synchronized void doSomething(){
        super.doSomething();
    }
}

重入鎖的高級功能:

  • 中斷響應(yīng)
    對于synchronized來說,如果一個線程正在證帶鎖,那么結(jié)果只有兩種情況,要么得到鎖繼續(xù)執(zhí)行,要么它就保持等待. 而使用重入鎖,則提供另外一種可能,那就是線程可以被中斷. 這種情況可以解決一般情況下的死鎖問題.
public class DeadLock implements Runnable{

    public static ReentrantLock lock1 = new ReentrantLock();

    public static ReentrantLock lock2 = new ReentrantLock();

    int lock;

    public DeadLock(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1){
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                }catch (InterruptedException e){}
                    lock2.lockInterruptibly();

            }else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                }catch (InterruptedException e){}
                    lock1.lockInterruptibly();

            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            if (lock1.isHeldByCurrentThread())
                lock1.unlock();
            if (lock2.isHeldByCurrentThread())
                lock2.unlock();
            System.out.println(Thread.currentThread().getId());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DeadLock deadLock1 = new DeadLock(1);
        DeadLock deadLock2 = new DeadLock(2);
        Thread t1 = new Thread(deadLock1);
        Thread t2 = new Thread(deadLock2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        t2.interrupt();

    }
}

在上面程序中,如果t1 先占用lock1 在占用lock2,t2 先占用lock2 再占用lock1,很容易發(fā)生 : 在t1去占用lock2時,lock2還沒有被釋放,或者t2去占用lock1時,lock1還沒有被釋放.這就會造成等待現(xiàn)象.但是在程序最后,將t2線程終止,此時t2線程接收到命令后會中斷自己,然后t2釋放鎖,由t1占用,就會解決死鎖問題.

  • 限時等待
    通常,一個線程拿不到鎖,可能是因為死鎖,也可能是因為饑餓,但是如果給定一個等待時間,讓線程自動放棄,就會解決這個問題.
    我們可以用tryLock()方法對線程進行限時等待的限制.

tryLock()方法有兩個參數(shù),第一個是等待時長,第二個是計時單位,如果超過給定時間還沒有得到鎖就會返回false,如果拿到鎖就會返回true. 如以下例子:

public class TimeLock implements Runnable{
    public static ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)){
                Thread.sleep(6000);
            }else {
                System.out.println("get lock failed");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            if (lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        TimeLock timeLock = new TimeLock();
        Thread t1 = new Thread(timeLock);
        Thread t2 = new Thread(timeLock);
        t1.start();
        t2.start();
    }
}

當(dāng)t1 或者 t2其中一個線程拿到鎖以后,會占用鎖6秒鐘,所以第二個線程會在五秒內(nèi)嘗試獲得失敗.避免了線程等待.
lock.tryLock()也可以用不傳遞人和參數(shù),代表如果鎖沒有被其他線程占用就會返回true,反之返回false.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市压固,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖稚叹,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拿诸,居然都是意外死亡扒袖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門亩码,熙熙樓的掌柜王于貴愁眉苦臉地迎上來季率,“玉大人,你說我怎么就攤上這事描沟§海” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵吏廉,是天一觀的道長泞遗。 經(jīng)常有香客問我,道長席覆,這世上最難降的妖魔是什么史辙? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮佩伤,結(jié)果婚禮上聊倔,老公的妹妹穿的比我還像新娘。我一直安慰自己畦戒,他們只是感情好方库,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著障斋,像睡著了一般纵潦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上垃环,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天邀层,我揣著相機與錄音,去河邊找鬼遂庄。 笑死寥院,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涛目。 我是一名探鬼主播秸谢,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼凛澎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了估蹄?” 一聲冷哼從身側(cè)響起塑煎,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臭蚁,沒想到半個月后最铁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡垮兑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年冷尉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片系枪。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡雀哨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嗤无,到底是詐尸還是另有隱情震束,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布当犯,位于F島的核電站垢村,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嚎卫。R本人自食惡果不足惜嘉栓,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拓诸。 院中可真熱鬧侵佃,春花似錦、人聲如沸奠支。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倍谜。三九已至迈螟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尔崔,已是汗流浹背答毫。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留季春,地道東北人洗搂。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耘拇。 傳聞我的和親對象是個殘疾皇子撵颊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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