首頁 > 軟體

Java執行緒的排程與優先順序詳解

2022-03-02 13:00:09

由於CPU的計算頻率非常高,每秒計算數十億次,因此可以將CPU的時間從毫秒的維度進行分段,每一小段叫作一個CPU時間片。

目前作業系統中主流的執行緒排程方式是:基於CPU時間片方式進行執行緒排程。執行緒只有得到CPU時間片才能執行指令,處於執行狀態,沒有得到時間片的執行緒處於就緒狀態,等待系統分配下一個CPU時間片。由於時間片非常短,在各個執行緒之間快速地切換,因此表現出來的特徵是很多個執行緒在“同時執行”或者“並行執行”。

執行緒的排程模型目前主要分為兩種:分時排程模型和搶佔式排程模型。

(1) 分時排程模型:系統平均分配CPU的時間片,所有執行緒輪流佔用CPU,即在時間片排程的分配上所有執行緒“人人平等”

(2) 搶佔式排程模型:系統按照執行緒優先順序分配CPU時間片。優先順序高的執行緒優先分配CPU時間片,如果所有就緒執行緒的優先順序相同,那麼會隨機選擇一個,優先順序高的執行緒獲取的CPU時間片相對多一些。

由於目前大部分作業系統都是使用搶佔式排程模型進行執行緒排程,Java的執行緒管理和排程是委託給作業系統完成的,與之相對應,Java的執行緒排程也是使用搶佔式排程模型,因此Java的執行緒都有優先順序。

在Thread類中有一個範例屬性和兩個實體方法,專門用於進行執行緒優先順序相關的操作。與執行緒優先順序相關的成員屬性為:

// 儲存Thread執行緒範例的優先順序,1~10之間
private int priority;
// 獲取執行緒優先順序
public final int getPriority(){//...}
// 設定執行緒優先順序
public final void setPriority(int priority){//...}

Thread範例的priority屬性預設是級別5,對應的類常數是NORM_PRIORITY。優先順序最大值為10,最小值為1,Thread類中定義的三個優先順序常數如下:

 public final static int MIN_PRIORITY = 1;
 public final static int NORM_PRIORITY = 5;
 public final static int MAX_PRIORITY = 10;

Java中使用搶佔式排程模型進行執行緒排程。priority範例屬性的優先順序越高,執行緒獲得CPU時間片的機會就越多,但也不是絕對的。

範例:

1、定義一個執行緒執行體,非同步執行:

public class ThreadDemo extends Thread {
    private  long num = 0;
    public long getNum() {
        return num;
    }
    @Override
    public void run() {
        // 執行緒執行體:死迴圈
       for(int i=0;;i++){
           num++;
       }
    }
}

2、建立10個執行緒,並設定不同的執行緒優先順序,來執行執行緒執行體:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo[] threads = new ThreadDemo[10];
        for(int i=0;i<threads.length;i++){
            threads[i] = new ThreadDemo();
            // 設定執行緒優先順序1~10
            threads[i].setPriority(i+1);
        }
        // 啟動執行緒
        for(int i=0;i<threads.length;i++){
            threads[i].start();
        }
        // 等待執行緒1s
        Thread.sleep(1000);
        // 停止執行緒
        for(int i=0;i<threads.length;i++){
            threads[i].stop();
        }
        for(int i=0;i<threads.length;i++){
            System.out.println(threads[i].getName()
                    +"-優先順序為-"+threads[i].getPriority()
                    +"-機會值為-"+threads[i].getNum());
        }
    }
}

線上程的run()方法中,設定了一個沒有條件判斷表示式的for迴圈,這是一個死迴圈,執行緒啟動之後,永遠也不會退出,直到執行緒被停止。那麼,問題來了:如何停止這10個執行緒呢?這裡使用Thread類的stop()實體方法,該方法的作用是終止執行緒的執行。

Thread類的stop()實體方法是一個過時的方法,也是一個不安全的方法。這裡的安全指的是系統資源(檔案、網路連線等)的安全——stop()實體方法可能導致資源狀態不一致,或者說資源出現問題時很難定位。在實際開發過程中,不建議使用stop()實體方法。

3、執行結果:

Thread-0-優先順序為-1-機會值為-0
Thread-1-優先順序為-2-機會值為-0
Thread-2-優先順序為-3-機會值為-0
Thread-3-優先順序為-4-機會值為-0
Thread-4-優先順序為-5-機會值為-3038296
Thread-5-優先順序為-6-機會值為-4473657
Thread-6-優先順序為-7-機會值為-2521154868
Thread-7-優先順序為-8-機會值為-2537430692
Thread-8-優先順序為-9-機會值為-2708120258
Thread-9-優先順序為-10-機會值為-2690953898

演示範例中10個執行緒停下來之後,某個執行緒的範例屬性opportunities的值越大,就表明該執行緒獲得的CPU時間片越多。分析案例的執行結果,可以得出以下結論:

(1) 整體而言,高優先順序的執行緒獲得的執行機會更多。從範例中可以看到:優先順序在5級以上的執行緒執行機會明顯偏多,整體對比非常明顯。

(2) 執行機會的獲取具有隨機性,優先順序高的不一定獲得的機會多。比如,例子中的thread-9比thread-8優先順序高,但是thread-9所獲得的機會反而偏少。

注意:

(1) 執行緒優先順序會提示排程器優先排程該執行緒,它僅僅是一個提示,排程器可以忽略它。

(2) 如果CPU比較忙,那麼優先順序高的執行緒會獲得更多的時間片,但是CPU閒時,優先順序幾乎沒作用。

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容! 


IT145.com E-mail:sddin#qq.com