1. 程式人生 > 實用技巧 >Java執行緒設定了優先順序,就一定生效嗎?Java執行緒的priority原始碼解析

Java執行緒設定了優先順序,就一定生效嗎?Java執行緒的priority原始碼解析

    歡迎大家搜尋“小猴子的技術筆記”關注我的公眾號,有問題可以及時和我交流。


    我們知道在構建一個執行緒物件的時候可以給執行緒設定一個優先順序,就像下面這樣:

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("設定執行緒的優先順序");
    }
}
public class MyRunnableTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.setPriority(10);
        thread.start();
    }
}

    或許你曾經有過這樣的想法,如果有多個執行緒的話,是不是可以按照這種優先順序設定的順序來啟動執行緒呢?我們來看下面這個例子:

public class MinPriority implements Runnable {
    @Override
    public void run() {
        System.out.println("執行緒的優先順序為1");
    }
}
public class NormalPriority implements Runnable {
    @Override
    public void run() {
        System.out.println("執行緒的優先順序為5");
    }
}
public class MaxPriority implements Runnable {
    @Override
    public void run() {
        System.out.println("執行緒的優先順序為10");
    }
}
public class ThreadPriorityTest {
    public static void main(String[] args) {
        Thread minThread = new Thread(new MinPriority());
        minThread.setPriority(1);
        Thread maxThread = new Thread(new MaxPriority());
        maxThread.setPriority(10);
        Thread normalThread = new Thread(new NormalPriority());
        normalThread.setPriority(5);
        minThread.start();
        maxThread.start();
        normalThread.start();
    }
}

    我模擬了三個不同優先級別的執行緒,在構建完成之後“同時”啟動,然後觀察結果。也請你嘗試把這些程式碼拷貝到你的開發工具中,然後嘗試執行“ThreadPriorityTest”,也許第一次你看到的結果是這樣的:

執行緒的優先順序為10
執行緒的優先順序為5
執行緒的優先順序為1

    你會很開心,因為它按照你的預期來輸出了。但是,請嘗試多執行幾次“ThreadPriorityTest”你也許會發現有其他的不同的結果:

執行緒的優先順序為5
執行緒的優先順序為10
執行緒的優先順序為1

    看到上面結果之後,回過頭來看我們最初設定的執行緒的優先順序貌似並沒有起到什麼作用。這到底是為什麼呢?彆著急!我們先來過一遍設定執行緒優先順序的原始碼:

public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

    首先聲明瞭一個執行緒組物件,然後“checkAccess()”進行了安全檢查,緊接著就是判斷我們傳遞過來的優先順序的值,判斷它是不是低於最小的優先順序,高於最大的優先順序,如果滿足上述條件的話,就直接丟擲引數不合法的異常。
執行緒Thread類提供了三個優先順序的常量:

// 可設定最小優先順序
public final static int MIN_PRIORITY = 1;
// 預設的優先順序,如果沒設定的話,預設為此值
public final static int NORM_PRIORITY = 5;
// 可設定最大優先順序
public final static int MAX_PRIORITY = 10;

    原始碼中比較重要的就是“((g = getThreadGroup()) != null)”的判斷,第一步先通過“getThreadGroup()”方法獲取到當前的執行緒組賦值給“g”。獲取執行緒組“getThreadGroup()”方法的原始碼如下:


public final ThreadGroup getThreadGroup() {
    return group;
}

    拿到返回的執行緒組之後判斷我們顯示設定的執行緒優先順序的值是否大於了執行緒組的優先順序,如果大於了,就設定為執行緒組的優先順序。

    最後就是通過“setPriority0(priority = newPriority)”方法給執行緒賦值:

private native void setPriority0(int newPriority);

    可以看到最後設定執行緒的這個方法是呼叫的本地方法,那麼就是交由底層去實現的。

    其實執行緒的優先順序設定可以理解為執行緒搶佔CPU時間片的概率,雖然概率比較大,但是它不一定就是按照優先順序的順序去搶佔CPU時間片的,具體的執行順序還是要根據誰先搶到了CPU的時間片,誰就先來執行。

    因此千萬不要把設定執行緒的優先順序當做是執行緒實際啟動的優先順序哦!