【Java並發編程實戰】----- AQS(三):阻塞、喚醒:LockSupport


在上篇博客(【Java並發編程實戰】----- AQS(二):獲取鎖、釋放鎖)中提到,當一個線程加入到CLH隊列中時,如果不是頭節點是需要判斷該節點是否需要掛起;在釋放鎖后,需要喚醒該線程的繼任節點

lock方法,在調用acquireQueued():

if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;

在acquireQueued()中調用parkAndCheckInterrupt()來掛起當前線程:

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

調用LockSupport.park()方法。對於park():為了線程調度,在許可可用之前禁用當前線程。

釋放鎖后,需要喚醒該線程繼任節點:

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

在release方法中調用unparkSuccessor()來喚醒該線程的繼任節點。在unparkSuccessor()方法中通過LockSupport.unpark()來喚醒。unpark():如果給定線程的許可尚不可用,則使其可用。

LockSupport

LockSupport是用來創建鎖和其他同步類的基本線程阻塞原語。每個使用LockSupport的線程都會與一個許可關聯,如果該許可可用,並且可在進程中使用,則調用park()將會立即返回,否則可能阻塞。如果許可尚不可用,則可以調用 unpark 使其可用。但是注意許可不可重入,也就是說只能調用一次park()方法,否則會一直阻塞。

LockSupport.park()、LockSupport.unpark()的作用分別是阻塞線程和解除阻塞線程,且park()和unpark()不會遇到“Thread.suspend ()和 Thread.resume所可能引發的死鎖”問題。當然park()、unpark()是成對使用。

park():如果許可可用,則使用該許可,並且該調用立即返回;否則,為線程調度禁用當前線程,並在發生以下三種情況之一以前,使其處於休眠狀態:

  • 其他某個線程將當前線程作為目標調用 unpark;或者
  • 其他某個線程中斷當前線程;或者
  • 該調用不合邏輯地(即毫無理由地)返回。

    其源碼實現如下:

    public static void park() {
            unsafe.park(false, 0L);
        }

    unpark:如果給定線程的許可尚不可用,則使其可用。如果線程在 park 上受阻塞,則它將解除其阻塞狀態。否則,保證下一次調用 park 不會受阻塞。如果給定線程尚未啟動,則無法保證此操作有任何效果。

    其源代碼如下:

    public static void unpark(Thread thread) {
            if (thread != null) { 
                Object lock = unsafe.getObject(thread, lockOffset);
                synchronized (lock) { 
                    if (thread.isAlive()) { 
                        unsafe.unpark(thread); 
                    } 
                } 
            } 
        }

     

    一般來說park()、unpark()是成對出現的,同時unpark必須要在park執行之后執行,當然並不是說沒有不調用unpark線程就會一直阻塞,park有一個方法,它帶了時間戳(parkNanos(long nanos):為了線程調度禁用當前線程,最多等待指定的等待時間,除非許可可用。)

     

    參考資料

    1、LockSupport的park和unpark的基本使用,以及對線程中斷的響應性


  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM