成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

實(shí)現(xiàn)死鎖的兩種方式以及ReentrantLock的額外功能

waltr / 3325人閱讀

摘要:實(shí)現(xiàn)死鎖的方法有兩種,一種是使用同步代碼塊,另一種是使用重入鎖。但是如果調(diào)用帶超時(shí)的方法,那么如果線程在等待時(shí)被中斷,將拋出一個(gè)異常,這是一個(gè)非常有用的特性,因?yàn)樗试S程序打破死鎖。

思路:

死鎖是指在多線程環(huán)境下的這么一種場(chǎng)景,兩個(gè)(多個(gè))線程在分別拿到自己的鎖時(shí)嘗試獲取對(duì)方的鎖,由于必須等待對(duì)方釋放鎖才能獲取,然而雙方誰(shuí)也不肯先釋放自己的鎖, 導(dǎo)致雙方誰(shuí)都無(wú)法繼續(xù)執(zhí)行。
通過(guò)一個(gè)實(shí)現(xiàn)runnable接口的類實(shí)例作為兩個(gè)線程的執(zhí)行對(duì)象,在該類中有兩個(gè)Object的靜態(tài)變量作為鎖.通過(guò)該類的一個(gè)開(kāi)關(guān)變量實(shí)現(xiàn)在同一個(gè)run方法中執(zhí)行兩段不同的邏輯,一個(gè)先獲取鎖1, 再獲取鎖2,另一個(gè)分支則剛好相反。
為了使第一個(gè)執(zhí)行的線程在拿到第二個(gè)鎖之前失去cpu執(zhí)行權(quán),方便構(gòu)造死鎖場(chǎng)景,在嘗試獲取第二個(gè)鎖之前,讓線程休眠一段時(shí)間,因?yàn)閟leep()方法不會(huì)釋放鎖。
實(shí)現(xiàn)死鎖的方法有兩種,一種是使用synchronized同步代碼塊,另一種是使用reentrantlock重入鎖。
使用同步代碼塊實(shí)現(xiàn)死鎖
代碼

public class TestDeadLock implements Runnable {

//開(kāi)關(guān)
private boolean       flag;
//鎖1
private static Object lock1 = new Object();
//鎖2
private static Object lock2 = new Object();

public TestDeadLock(boolean flag) {
    this.flag = flag;
}

@Override
public void run() {
    if (flag) {
        synchronized (lock1) {
            System.out.println(flag + "線程拿到了lock1");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock2) {
                System.out.println(flag + "線程拿到了lock2");
            }
        }
    } else {
        synchronized (lock2) {
            System.out.println(flag + "線程拿到了lock2");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock1) {
                System.out.println(flag + "線程拿到了lock1");
            }
        }
    }
}

public static void main(String[] args) {
    Thread thread1 = new Thread(new TestDeadLock(true));
    Thread thread2 = new Thread(new TestDeadLock(false));
    thread1.start();
    thread2.start();
}

}
運(yùn)行結(jié)果

true線程拿到了lock1
false線程拿到了lock2
使用ReentrantLock實(shí)現(xiàn)死鎖
代碼

public class TestDeadLock2 implements Runnable{

private boolean flag;
private static ReentrantLock lock1=new ReentrantLock();
private static ReentrantLock lock2=new ReentrantLock();

public TestDeadLock2(boolean flag) {
    this.flag = flag;
}

@Override
public void run() {
    try {
        if(flag){
            lock1.lock();
            System.out.println(flag + "線程獲取了Lock1");
            TimeUnit.SECONDS.sleep(1);
            lock2.lock();
            System.out.println(flag+"線程獲取了Lock2");
        }else{
            lock2.lock();
            System.out.println(flag + "線程獲取了Lock2");
            TimeUnit.SECONDS.sleep(1);
            lock1.lock();
            System.out.println(flag+"線程獲取了Lock1");
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        if(lock1.isHeldByCurrentThread()){
            lock1.unlock();
        }
        if(lock2.isHeldByCurrentThread()){
            lock2.unlock();
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    Thread thread1=new Thread(new TestDeadLock2(true));
    Thread thread2=new Thread(new TestDeadLock2(false));
    thread1.start();
    thread2.start();
    thread1.join();
    thread2.join();
    System.out.println("主線程已結(jié)束");
}

}
運(yùn)行結(jié)果

false線程獲取了Lock2
true線程獲取了Lock1
ReentrantLock和Synchronized的區(qū)別,具體可見(jiàn)
Java中的ReentrantLock和synchronized兩種鎖定機(jī)制的對(duì)比

。總的來(lái)說(shuō),ReentrantLock所提供的功能比Synchronized要豐富的多,比如

lockInterruptibly
API簽名

public void lockInterruptibly() throws InterruptedException

代碼

public class TestDeadLock3 implements Runnable {

private boolean      flag;
static ReentrantLock lock1 = new ReentrantLock();
static ReentrantLock lock2 = new ReentrantLock();

public TestDeadLock3(boolean flag) {
    this.flag = flag;
}

@Override
public void run() {

    try {
        if (flag) {
            //可中斷地加鎖
            lock1.lockInterruptibly();
            System.out.println(flag + "線程獲取了lock1");
            TimeUnit.SECONDS.sleep(1);
            lock2.lockInterruptibly();
            System.out.println(flag + "線程獲取了lock2");
        } else {
            lock2.lockInterruptibly();
            System.out.println(flag + "線程獲取lock2");
            TimeUnit.SECONDS.sleep(1);
            lock1.lockInterruptibly();
            System.out.println(flag + "線程獲取了lock1");
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        if (lock1.isHeldByCurrentThread()) {
            lock1.unlock();
            System.out.println(flag + "線程釋放lock1鎖");
        }
        if (lock2.isHeldByCurrentThread()) {
            lock2.unlock();
            System.out.println(flag + "線程釋放lock2鎖");
        }
        System.out.println(flag + "線程已退出");
    }

}

public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(new TestDeadLock3(true));
    Thread thread2 = new Thread(new TestDeadLock3(false));
    thread1.start();
    thread2.start();
    //主線程休眠5秒
    TimeUnit.SECONDS.sleep(5);
    thread1.interrupt();
}

}
運(yùn)行結(jié)果

true線程獲取了lock1
false線程獲取lock2
java.lang.InterruptedException

                                    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:896)
                                    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
                                    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)

true線程釋放lock1鎖

                                    at com.akane.test.reentrantlock.TestDeadLock3.run(TestDeadLock3.java:31)

true線程已退出

                                    at java.lang.Thread.run(Thread.java:744)

false線程獲取了lock1
false線程釋放lock1鎖
false線程釋放lock2鎖
false線程已退出

Process finished with exit code 0
關(guān)于interrupt的用法

synchronized在獲鎖的過(guò)程中是不能被中斷的,意思是說(shuō)如果產(chǎn)生了死鎖,則不可能被中斷(請(qǐng)參考后面的測(cè)試?yán)樱?。與synchronized功能相似的reentrantLock.lock()方法也是一樣,它也不可中斷的,即如果發(fā)生死鎖,那么reentrantLock.lock()方法無(wú)法終止,如果調(diào)用時(shí)被阻塞,則它一直阻塞到它獲取到鎖為止。但是如果調(diào)用帶超時(shí)的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果線程在等待時(shí)被中斷,將拋出一個(gè)InterruptedException異常,這是一個(gè)非常有用的特性,因?yàn)樗试S程序打破死鎖。你也可以調(diào)用reentrantLock.lockInterruptibly()方法,它就相當(dāng)于一個(gè)超時(shí)設(shè)為無(wú)限的tryLock方法
主線程對(duì)Thread1進(jìn)行了中斷,thread1拋出異常,異常被捕獲,在finally中釋放thread1獲得的鎖,線程2獲得需要的鎖,該線程得以繼續(xù)執(zhí)行,死鎖就被解決了

tryLock
當(dāng)然,ReentrantLock還提供了另外一個(gè)更好的方法解決死鎖問(wèn)題,那就是使用tryLock()方法,該方法會(huì)嘗試獲得鎖,如果成功,返回true,失敗則返回false。該方法不等待或等待一段時(shí)間就返回。

API簽名

public boolean tryLock() 立即返回
public boolean tryLock(long timeout, TimeUnit unit) 等待一段時(shí)間后返回

死鎖的原因在于吃著碗里的看著鍋里的,我們讓線程拿到一個(gè)鎖之后無(wú)論是否拿到第二個(gè)鎖,都釋放已經(jīng)拿到的鎖,可以將此邏輯放入finally中,配合外層的while(true)多次重復(fù)嘗試,如果成功獲取兩個(gè)鎖,則釋放兩個(gè)鎖的同時(shí)推出while循環(huán),以下是代碼實(shí)現(xiàn),線程睡眠時(shí)間由1秒改為1毫秒,減少測(cè)試需要的時(shí)間

代碼

public class TestDeadLock4 implements Runnable{

private boolean      flag;
static ReentrantLock lock1 = new ReentrantLock();
static ReentrantLock lock2 = new ReentrantLock();
//統(tǒng)計(jì)發(fā)生死鎖的次數(shù)
private static int count;

public TestDeadLock4(boolean flag) {
    this.flag = flag;
}

@Override
public void run() {
    if(flag){
        while (true) {
            if(lock1.tryLock()){
                System.out.println(flag+"線程獲得了lock1");
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                    try {
                        if(lock2.tryLock()){
                            System.out.println(flag+"獲得了lock2");
                        }
                    } finally {
                        //同時(shí)獲得Lock1和lock2,沒(méi)有發(fā)生死鎖,任務(wù)完成,退出循環(huán)
                        if(lock1.isHeldByCurrentThread()&&lock2.isHeldByCurrentThread()){
                            System.out.println(flag+"線程執(zhí)行完畢"+"---------------------");
                            lock1.unlock();
                            lock2.unlock();
                            break;
                        }else{
                            //說(shuō)明發(fā)生了死鎖,只需要釋放lock1
                            count++;
                            System.out.println("發(fā)生了"+count+"次死鎖");
                            lock1.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }else{
        while (true) {
            if(lock2.tryLock()){
                System.out.println(flag+"線程獲得了lock2");
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                    try {
                        if(lock1.tryLock()){
                            System.out.println(flag+"線程獲得了lock1");
                        }
                    } finally {
                        if(lock1.isHeldByCurrentThread()&&lock2.isHeldByCurrentThread()){
                            System.out.println(flag+"線程執(zhí)行完畢"+"---------------------");
                            lock1.unlock();
                            lock2.unlock();
                            break;
                        }else{
                            count++;
                            System.out.println("發(fā)生了"+count+"次死鎖");
                            lock2.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(new TestDeadLock4(true));
    Thread thread2 = new Thread(new TestDeadLock4(false));
    thread1.start();
    thread2.start();
}

}
運(yùn)行結(jié)果(部分)

全選復(fù)制放進(jìn)筆記true線程獲得了lock1
false線程獲得了lock2
發(fā)生了3358次死鎖
false獲得了lock1
false線程執(zhí)行完畢---------------------
true線程獲得了lock1
true獲得了lock2
true線程執(zhí)行完畢---------------------

Process finished with exit code 0
公平鎖
除此之外,ReentrantLock還有能實(shí)現(xiàn)線程公平獲取鎖的功能,所謂的公平,指的是在申請(qǐng)獲取鎖的隊(duì)列中,排在前面的線程總是優(yōu)先獲得需要的鎖,Synchronized同步獲得鎖的方式是非公平的,舉個(gè)例子,線程A和B都嘗試獲得C持有的鎖,當(dāng)C釋放該鎖時(shí),A和B誰(shuí)能獲得該鎖是不確定的,也就是非公平的,而ReentrantLock提供公平地,即先來(lái)后到地獲取鎖的方式。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65534.html

相關(guān)文章

  • Synchronize和ReentrantLock區(qū)別

    摘要:的鎖是非公平鎖,默認(rèn)情況下也是非公平鎖,但可以通過(guò)帶布爾值的構(gòu)造函數(shù)要求使用公平鎖。有序性,是保證線程內(nèi)串行語(yǔ)義,避免指令重排等。公平性是減少線程饑餓個(gè)別線程長(zhǎng)期等待鎖,但始終無(wú)法獲取情況發(fā)生的一個(gè)辦法。 目錄介紹 1.Synchronize和ReentrantLock區(qū)別 1.1 相似點(diǎn) 1.2 區(qū)別 1.3 什么是線程安全問(wèn)題?如何理解 1.4 線程安全需要保證幾個(gè)基本特性 ...

    FuisonDesign 評(píng)論0 收藏0
  • Java多線程&高并發(fā)

    摘要:線程啟動(dòng)規(guī)則對(duì)象的方法先行發(fā)生于此線程的每一個(gè)動(dòng)作。所以局部變量是不被多個(gè)線程所共享的,也就不會(huì)出現(xiàn)并發(fā)問(wèn)題。通過(guò)獲取到數(shù)據(jù),放入當(dāng)前線程處理完之后將當(dāng)前線程中的信息移除。主線程必須在啟動(dòng)其他線程后立即調(diào)用方法。 一、線程安全性 定義:當(dāng)多個(gè)線程訪問(wèn)某個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式,或者這些線程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個(gè)類都能表現(xiàn)出正確的行...

    SQC 評(píng)論0 收藏0
  • Java 同步鎖

    摘要:如果同一個(gè)線程再次請(qǐng)求該鎖,計(jì)數(shù)器會(huì)遞增,每次占有的線程退出同步代碼塊時(shí)計(jì)數(shù)器會(huì)遞減,直至減為時(shí)鎖才會(huì)被釋放。表示或在該上的所有線程的個(gè)數(shù)用來(lái)實(shí)現(xiàn)重入鎖的計(jì)數(shù)。只有兩種可能的值表示沒(méi)有需要喚醒的線程表示要喚醒一個(gè)繼任線程來(lái)競(jìng)爭(zhēng)鎖。 一、synchronized 1.類型 (1)對(duì)象鎖 對(duì)象鎖是作用在實(shí)例方法或者一個(gè)對(duì)象實(shí)例上面的 一個(gè)類可以有多個(gè)實(shí)例對(duì)象,因此一個(gè)類的對(duì)象鎖可能會(huì)有多個(gè)...

    xi4oh4o 評(píng)論0 收藏0
  • 40道阿里巴巴JAVA研發(fā)崗多線程面試題詳解,你能答出多少

    摘要:但是單核我們還是要應(yīng)用多線程,就是為了防止阻塞。多線程可以防止這個(gè)問(wèn)題,多條線程同時(shí)運(yùn)行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會(huì)影響其它任務(wù)的執(zhí)行。 1、多線程有什么用?一個(gè)可能在很多人看來(lái)很扯淡的一個(gè)問(wèn)題:我會(huì)用多線程就好了,還管它有什么用?在我看來(lái),這個(gè)回答更扯淡。所謂知其然知其所以然,會(huì)用只是知其然,為什么用才是知其所以然,只有達(dá)到知其然知其所以然的程度才可以說(shuō)是把一個(gè)知識(shí)點(diǎn)...

    lpjustdoit 評(píng)論0 收藏0
  • Java面試題

    摘要:近段時(shí)間在準(zhǔn)備實(shí)習(xí)的面試,在網(wǎng)上看到一份面試題,就慢慢試著做,爭(zhēng)取每天積累一點(diǎn)點(diǎn)。現(xiàn)在每天給自己在面試題編寫(xiě)的任務(wù)是題,有時(shí)候忙起來(lái)可能就沒(méi)有時(shí)間寫(xiě)了,但是爭(zhēng)取日更,即使當(dāng)天沒(méi)更也會(huì)在之后的更新補(bǔ)上。 ????近段時(shí)間在準(zhǔn)備實(shí)習(xí)的面試,在網(wǎng)上看到一份面試題,就慢慢試著做,爭(zhēng)取每天積累一點(diǎn)點(diǎn)。????暫時(shí)手頭上的面試題只有一份,題量還是挺大的,有208題,所以可能講的不是很詳細(xì),只是我自...

    OnlyMyRailgun 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<