国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

實現死鎖的兩種方式以及ReentrantLock的額外功能

waltr / 3318人閱讀

摘要:實現死鎖的方法有兩種,一種是使用同步代碼塊,另一種是使用重入鎖。但是如果調用帶超時的方法,那么如果線程在等待時被中斷,將拋出一個異常,這是一個非常有用的特性,因為它允許程序打破死鎖。

思路:

死鎖是指在多線程環境下的這么一種場景,兩個(多個)線程在分別拿到自己的鎖時嘗試獲取對方的鎖,由于必須等待對方釋放鎖才能獲取,然而雙方誰也不肯先釋放自己的鎖, 導致雙方誰都無法繼續執行。
通過一個實現runnable接口的類實例作為兩個線程的執行對象,在該類中有兩個Object的靜態變量作為鎖.通過該類的一個開關變量實現在同一個run方法中執行兩段不同的邏輯,一個先獲取鎖1, 再獲取鎖2,另一個分支則剛好相反。
為了使第一個執行的線程在拿到第二個鎖之前失去cpu執行權,方便構造死鎖場景,在嘗試獲取第二個鎖之前,讓線程休眠一段時間,因為sleep()方法不會釋放鎖。
實現死鎖的方法有兩種,一種是使用synchronized同步代碼塊,另一種是使用reentrantlock重入鎖。
使用同步代碼塊實現死鎖
代碼

public class TestDeadLock implements Runnable {

//開關
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();
}

}
運行結果

true線程拿到了lock1
false線程拿到了lock2
使用ReentrantLock實現死鎖
代碼

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("主線程已結束");
}

}
運行結果

false線程獲取了Lock2
true線程獲取了Lock1
ReentrantLock和Synchronized的區別,具體可見
Java中的ReentrantLock和synchronized兩種鎖定機制的對比

。總的來說,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();
}

}
運行結果

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
關于interrupt的用法

synchronized在獲鎖的過程中是不能被中斷的,意思是說如果產生了死鎖,則不可能被中斷(請參考后面的測試例子)。與synchronized功能相似的reentrantLock.lock()方法也是一樣,它也不可中斷的,即如果發生死鎖,那么reentrantLock.lock()方法無法終止,如果調用時被阻塞,則它一直阻塞到它獲取到鎖為止。但是如果調用帶超時的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果線程在等待時被中斷,將拋出一個InterruptedException異常,這是一個非常有用的特性,因為它允許程序打破死鎖。你也可以調用reentrantLock.lockInterruptibly()方法,它就相當于一個超時設為無限的tryLock方法
主線程對Thread1進行了中斷,thread1拋出異常,異常被捕獲,在finally中釋放thread1獲得的鎖,線程2獲得需要的鎖,該線程得以繼續執行,死鎖就被解決了

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

API簽名

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

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

代碼

public class TestDeadLock4 implements Runnable{

private boolean      flag;
static ReentrantLock lock1 = new ReentrantLock();
static ReentrantLock lock2 = new ReentrantLock();
//統計發生死鎖的次數
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 {
                        //同時獲得Lock1和lock2,沒有發生死鎖,任務完成,退出循環
                        if(lock1.isHeldByCurrentThread()&&lock2.isHeldByCurrentThread()){
                            System.out.println(flag+"線程執行完畢"+"---------------------");
                            lock1.unlock();
                            lock2.unlock();
                            break;
                        }else{
                            //說明發生了死鎖,只需要釋放lock1
                            count++;
                            System.out.println("發生了"+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+"線程執行完畢"+"---------------------");
                            lock1.unlock();
                            lock2.unlock();
                            break;
                        }else{
                            count++;
                            System.out.println("發生了"+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();
}

}
運行結果(部分)

全選復制放進筆記true線程獲得了lock1
false線程獲得了lock2
發生了3358次死鎖
false獲得了lock1
false線程執行完畢---------------------
true線程獲得了lock1
true獲得了lock2
true線程執行完畢---------------------

Process finished with exit code 0
公平鎖
除此之外,ReentrantLock還有能實現線程公平獲取鎖的功能,所謂的公平,指的是在申請獲取鎖的隊列中,排在前面的線程總是優先獲得需要的鎖,Synchronized同步獲得鎖的方式是非公平的,舉個例子,線程A和B都嘗試獲得C持有的鎖,當C釋放該鎖時,A和B誰能獲得該鎖是不確定的,也就是非公平的,而ReentrantLock提供公平地,即先來后到地獲取鎖的方式。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65534.html

相關文章

  • Synchronize和ReentrantLock區別

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

    FuisonDesign 評論0 收藏0
  • Java多線程&高并發

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

    SQC 評論0 收藏0
  • Java 同步鎖

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

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

    摘要:但是單核我們還是要應用多線程,就是為了防止阻塞。多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執行讀取數據阻塞,也不會影響其它任務的執行。 1、多線程有什么用?一個可能在很多人看來很扯淡的一個問題:我會用多線程就好了,還管它有什么用?在我看來,這個回答更扯淡。所謂知其然知其所以然,會用只是知其然,為什么用才是知其所以然,只有達到知其然知其所以然的程度才可以說是把一個知識點...

    lpjustdoit 評論0 收藏0
  • Java面試題

    摘要:近段時間在準備實習的面試,在網上看到一份面試題,就慢慢試著做,爭取每天積累一點點。現在每天給自己在面試題編寫的任務是題,有時候忙起來可能就沒有時間寫了,但是爭取日更,即使當天沒更也會在之后的更新補上。 ????近段時間在準備實習的面試,在網上看到一份面試題,就慢慢試著做,爭取每天積累一點點。????暫時手頭上的面試題只有一份,題量還是挺大的,有208題,所以可能講的不是很詳細,只是我自...

    OnlyMyRailgun 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<