LockSupper介紹:
所有的方法都是靜態方法,可以讓線程在任意位置阻塞,當然阻塞之後肯定得有喚醒的方法。
源碼:LockSupper不能被實例化(構造函數是私有的)!
源碼解釋參考:
https://blog.csdn.net/secsf/article/details/78560013
主要有兩類方法:park
和 unpark
。
爲什麼叫park呢,park英文意思爲停車。我們如果把Thread看成一輛車的話,park就是讓車停下,unpark就是讓車啓動然後跑起來。
調用了park方法後當前線程被阻塞,必須由unpark方法喚醒,不然會一直阻塞
park可以帶參數
源碼:
* <p>This method does <em>not</em> report which of these caused the
* method to return. Callers should re-check the conditions which caused
* the thread to park in the first place. Callers may also determine,
* for example, the interrupt status of the thread upon return.
*
* @param blocker the synchronization object responsible for this
* thread parking
* @since 1.6
*/
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
park()裏面傳遞一個對象,可以通過調用getBlocker()來獲得,
不過只有在線程已經堵塞的時候纔會獲得這個對象,當線程不再堵塞的時候
將無法在或的這個對象。你想一下就會明白,因爲許可只有一次,
當你第一次堵塞的時候傳遞了一個對象,當獲得許可之前你都可以獲得這個對象,
但是如果一旦這個線程獲得了許可,就不可以在獲得這個對象了。
假如有一輛載滿香豬的貨車過紅綠燈,當紅燈堵塞的時候,
所有的人都可以看到貨車裏面載的是香豬,但是當綠燈了,
貨車獲得許可,所有的人都無法知道貨車下次再經過的時候會帶什麼貨,
有些牽強,但希望幫助理解一下。
栗子代碼:
package com.demo;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* @Description
* @Author by mocar小師兄
* @Date 2020/3/13 14:43
**/
public class LockSupportDemo {
private static Object object=new Object();
private static class ThreadTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t 開始");
synchronized (object){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t 獲得鎖");
LockSupport.park();
if (Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName() + "\t 被中斷");
}
System.out.println(Thread.currentThread().getName() + "\t 執行任務完成");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new ThreadTask());
Thread thread2 = new Thread(new ThreadTask());
System.out.println("Main主線程開始");
thread1.start();
thread2.start();
thread1.join(2000);
thread2.join(2000);
System.out.println("Main主線程結束");
}
}
結果顯示:
當調用了part方法後,線程被阻塞,線程調用join方法也無法繼續執行,會繼續被阻塞
正確用法:
package com.demo;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* @Description
* @Author by mocar小師兄
* @Date 2020/3/13 14:43
**/
public class LockSupportDemo {
private static Object object=new Object();
private static class ThreadTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t 開始");
synchronized (object){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t 獲得鎖");
if (Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName() + "\t 被中斷");
}
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t 執行任務完成");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new ThreadTask());
Thread thread2 = new Thread(new ThreadTask());
System.out.println("Main主線程開始");
thread1.start();
thread2.start();
System.out.println("兩個子線程已開啓,Main主線程等待兩秒");
TimeUnit.SECONDS.sleep(2);
LockSupport.unpark(thread1);
LockSupport.unpark(thread2);
thread1.interrupt();//中斷thread1,看中斷後是否會釋放鎖,即thread2是否能獲取鎖
/*thread1.join(2000);
thread2.join(2000);*/
System.out.println("Main主線程結束");
}
}
順序問題:
LockSupport.park()和LockSupport.unpark(thread1)執行順序先後沒有那麼嚴格,
即使Main主線先執行了LockSupport.unpark(thread1)語句,
才進入的子線程執行LockSupport.park(),子線程也會獲得許可執行part後面的代碼。
參考:
https://www.jianshu.com/p/f1f2cd289205