java併發編程的藝術(7)LockSupport

關於LockSupport工具類的使用

在閱讀aqs源碼的時候,經常會看到使用了LockSupport工具類,這個工具類裏面提供了兩個用於堵塞現線程和解除線程堵塞的接口:
park
unpark

核心源碼:

private static void setBlocker(Thread t, Object arg) {
    // Even though volatile, hotspot doesn't need a write barrier here.
    UNSAFE.putObject(t, parkBlockerOffset, arg);
}

/**
 * Makes available the permit for the given thread, if it
 * was not already available.  If the thread was blocked on
 * {@code park} then it will unblock.  Otherwise, its next call
 * to {@code park} is guaranteed not to block. This operation
 * is not guaranteed to have any effect at all if the given
 * thread has not been started.
 *
 * @param thread the thread to unpark, or {@code null}, in which case
 *        this operation has no effect
 */
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}


public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}

從源碼中的構造函數可以看到:
該類是不能夠被實例化的。

提供的方法大多數都是靜態方法

提供了一些靜態成員變量:

// Hotspot implementation via intrinsics API
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset;
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;

UNSAFE: 工具類
這是一種jdk內部提供的工具類,可以直接操控內存,被jdk廣泛用於自己的jar包裏面,提供一些對於java來說不安全的功能供java代碼調用。讓jdk能實現 更多的一些需要用native語言,C或者C++才能實現的功能。

看過Thread源碼的朋友應該知道thread裏面有一個
volatile Object parkBlocker;
成員變量,這個成員變量主要是提供給LockSupport所使用的。

通過demo測試發現:
LockSupport阻塞和解除阻塞線程直接操作的是Thread,
而Object的wait/notify它並不是直接對線程操作,它是被動的方法,它需要一個object來進行線程的掛起或喚醒。也就是說Thread在進行喚醒操作之後,還需要獲取到監視器纔可以繼續執行。
而LockSupport則不需要。

如果我們將unpark和park的順序進行調換,結果又會如何呢?
經過測試,不會有影響。反而更加具有靈活性。

線程的中斷性測試:
第一種,通過使用interrupt()的方式來進行線程中斷:
結果並沒有實際的效果,因爲interrupt()只不過是將線程的中斷狀態進行設置調整罷了。並沒有進行完整的中斷。因此需要加入一個開關來進行中斷處理:

/**
 * @author idea
 * @data 2019/2/1
 */
public class Demo2 implements Runnable{

    public static void main(String[] args) throws InterruptedException {
        Thread testThread=new Thread(new Demo2(),"InterruptionInJava");
        testThread.start();
        Thread.sleep(1000);
        //對該線程進行中斷測試
        testThread.interrupt();
        System.out.println("end");
    }

    @Override
    public void run() {
        while(true){
            if(!Thread.currentThread().isInterrupted()){
                System.out.println("this is a test!");
            }else{
                break;
            }
        }
    }
}

如果遇到了類似於下圖中的這種情況:線程堵塞
在這裏插入圖片描述
interrupt函數可以提供將該線程進行中斷的處理,不過可能會有相應的異常拋出。

parkBlockerOffset是unsafe包裏面的一個成員變量。由於目標線程可能是處於堵塞狀態,因此想要獲取相應的對象,需要通過一個parkBlockerOffset的內存偏移量來獲取對象信息。
LockSupport中的park方法可以設定相應的堵塞時間長度,防止一直堵塞。

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