提到等待喚醒機制最常想到的就是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
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL6dmaNRTSE9EMRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4QjN2MjMwkDMwEDNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
調用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()+"休眠結束");
}
}
使用喚醒機制成功喚醒。然後嘗試使用中斷線程
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喚醒在等待之前發生
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還支援逾時自動傳回等等
總結:
1.LockSupport通過park()和unpark()實作線程的等待喚醒。喚醒也可以使用中斷的方式,該方式并不會抛出異常也不會清除中斷标記
2.喚醒可以發生在等待機制之前就發生,且不需要擷取鎖