併發編程之LockSupport源碼分析及簡單使用

曾經面試被問到JAVA中實現線程掛起和喚醒有哪些方式,除了採用Object類中wait notify/notifyAll實現還有其他方式嗎?當時真心沒答上來,後來做了功課才知道還有LockSupport類中park/unpark可以實現。

大家如果瞭解AQS(全稱AbstractQueuedSynchronizer),就知道併發編程中很多類都是基於AQS實現的,例如ReentrantLock、 CountDownLatch、Semaphore等等。

通過分析AQS源碼,不難發現AbstractQueuedSynchronizer中ConditionObject內部類就採用LockSupport實現線程掛起和喚醒。

例如ConditionObject中await方法如下:

例如ConditionObject中signal方法如下:

ConditionObject中signal方法調用doSignal方法如下:

ConditionObject中doSignal調用外部類的transferForSignal方法如下:

我們可以看出LockSupport類中park/unpark同樣可以實現線程掛起和喚醒。其實如果大家看過我之前寫的‘手寫一個同步類容器(互聯網大廠面試題目)’文章,就知道文章有采用Lock/Condition await signalAll實現 更精確定位喚起的線程,它的底層實現就是LockSupport的park/unpark。

我們來分析LockSupport源碼:

通過LockSupport源碼設計我們知道它實現線程掛起和喚醒是基於Unsafe底層實現。代碼不是很複雜,我們這裏不做詳細

講解。

我們來找到Unsafe中park、unpark源碼:

由此,我們就完整的跟進了LockSupport類中park/unpark的設計理念。

現在我們通過一段簡單的代碼,來初步理解LockSupport如何掛起和喚醒線程。

package com.locksupport;

import java.util.concurrent.locks.LockSupport;

/**
 * LockSupport源碼分析、使用場景說明
 *
 * @author 小輝GE/小輝哥
 * <p>
 * 2019年8月30日 下午21:30:00
 */
public class LockSupportAnalysis {
	public static void main(String[] args) throws Exception {
		Thread thread = new Thread(() -> {
			System.out.println("begin......");
			// 當前線程wait
			LockSupport.park();
			System.out.println("end......");
		});
		thread.start();

		// Thread.sleep(1000);
		// 線程解除wait
		LockSupport.unpark(thread);
	}
}

測試輸出結果如下:

結果分析:

  1. LockSupport不需要在同步代碼塊裏。所以線程間也不需要維護一個共享的同步對象了,從而降低了使用時複雜度。
  2. unpark函數可以優先於park調用,所以不需要擔心線程間的執行先後順序。

以上代碼僅供參考,如有不當之處,歡迎指出!!!

更多幹貨,歡迎大家關注和聯繫我。期待和大家一起更好的交流、探討技術!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章