天天看點

LockSupport實作等待喚醒機制

提到等待喚醒機制最常想到的就是Object中的wait/notify以及Condition中await/signal。但是這兩種方式會有一定的缺陷比如:

1.在使用等待喚醒機制前需要先擷取鎖

2.等待一定是發生在喚醒之前的

那麼今天介紹的LockSupport在實作等待喚醒機制時就不需要擷取鎖

LockSupport實作等待喚醒機制依靠的是park()和unpark(thread)方法,這兩個方法都是LockSupport的靜态方法

每一個線程都會有一個許可證稱為permit。permit隻有兩個值,0和1預設情況下permit的值為0

調用unpark(thread)方法時,如果此時線程的permit為0,則會變成1.如果是1,則還是1

LockSupport實作等待喚醒機制

調用park()方法時,如果此時的permit是1,那麼會将permit設定為0并立即傳回。如果是0的話就會發生阻塞,測試需要調用unpark(thread)方法将permit設定為1線程将會被喚醒/或者中斷線程

代碼示範:

import java.util.concurrent.locks.LockSupport;

public class LockSupportTest {
    public static void main(String[] args) {
        Threadi threadi = new Threadi();
        threadi.start();
        try {
            Thread.sleep(3000);
            //三秒後喚醒
           LockSupport.unpark(threadi);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Threadi extends Thread{

    @Override
    public void run() {
            System.out.println(System.currentTimeMillis()+"該線程執行了,準備休眠");
            LockSupport.park();//使目前線程進行休眠
            System.out.println(System.currentTimeMillis()+"休眠結束");
    }
}


           
LockSupport實作等待喚醒機制

使用喚醒機制成功喚醒。然後嘗試使用中斷線程

import java.util.concurrent.locks.LockSupport;

public class LockSupportTest {
    public static void main(String[] args) {
        Threadi threadi = new Threadi();
        threadi.start();
        try {
            Thread.sleep(3000);
            threadi.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Threadi extends Thread{

    @Override
    public void run() {
            System.out.println(System.currentTimeMillis()+"該線程執行了,準備休眠"+this.isInterrupted());
            LockSupport.park();
            System.out.println(System.currentTimeMillis()+"休眠結束"+this.isInterrupted());

    }
}
           
LockSupport實作等待喚醒機制

我們可以看出這種喚醒機制并沒有抛出異常,并且中斷标志并不會清除

LockSupport喚醒在等待之前發生

import java.util.concurrent.locks.LockSupport;

public class LockSupportTest {
    public static void main(String[] args) {
        Threadi threadi = new Threadi();
        threadi.start();
        try {
            Thread.sleep(1000);
            System.out.println("開始喚醒線程");
            LockSupport.unpark(threadi);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Threadi extends Thread{

    @Override
    public void run() {
         try {
             System.out.println("線程先進入休眠");
             Thread.sleep(3000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
        System.out.println(System.currentTimeMillis()+"該線程執行了,開始等待");
            LockSupport.park();
            System.out.println(System.currentTimeMillis()+"休眠結束");

    }
}


           

上述代碼線上程threadi在開始等待之前就先進行了喚醒,那麼我們看一下結果:

LockSupport實作等待喚醒機制

我們可以看出線上程開始等待時直接就被喚醒了。

LockSupport還支援逾時自動傳回等等

總結:

1.LockSupport通過park()和unpark()實作線程的等待喚醒。喚醒也可以使用中斷的方式,該方式并不會抛出異常也不會清除中斷标記

2.喚醒可以發生在等待機制之前就發生,且不需要擷取鎖

繼續閱讀