簡體   English   中英

理解java線程中的“優先級”

[英]Understanding “priority” in java threads

我是java和線程世界的新手。我只是通過以下示例代碼: -

package com.alice.learnthread;

class NewThread implements Runnable{
Thread t;
long clicker=0;

private volatile boolean running=true;
NewThread(int p){
    t=new Thread(this);
    t.setPriority(p);
}
public void run(){
    while(running){
        clicker++;
    }
}
public void stop(){
    running=false;
}
public void start(){
    t.start();
}

}

 public class TestThread {
public static void main(String[] args){
    Thread r=Thread.currentThread();
    r.setPriority(Thread.MAX_PRIORITY);
    NewThread hi=new NewThread(Thread.NORM_PRIORITY+2);
    NewThread lo=new NewThread(Thread.NORM_PRIORITY-2);
    hi.start();
    lo.start();
    try{
        r.sleep(5000);
    }catch(InterruptedException e){
        System.out.println("caught");
    }
    hi.stop();
    lo.stop();
    try{
        hi.t.join();
        lo.t.join();
    }catch(InterruptedException e){
        System.out.println("cau1");
    }
    System.out.println("hi = "+hi.clicker+" lo="+lo.clicker);
}

}

但是根據書中的輸出,具有高優先級的線程應該具有更高的變量點擊器值。 但在我的情況下,變量點擊器的值對於優先級較低的線程比高優先級線程要高得多。輸出如下對我來說: -

hi = 2198713135 lo=2484053552

這是否意味着較低優先級的線程比較高優先級的線程獲得更多的CPU時間...我錯過了什么...在ubuntu和win7上的結果是相同的(較低優先級線程的較高的點擊者值)...

Java中的線程優先級不保證預期的行為。 這就像是對JVM的暗示。 實際行為取決於底層操作系統。

另外,請閱讀關於合作與先發制人線程的這個不錯的小段落: http//www.cafeaulait.org/course/week11/32.html

正如蘇爾所說,優先權更多的是提示而不是與JVM的合同。 在您的情況下,您的結果可以用幾種理論來解釋:

  • 第二個線程運行得更快,因為它獲得了第一個線程編譯的好處,並在第一個線程之后停止。
  • while循環檢查volatile變量的值的事實迫使jvm實現該值,並且在此期間可以給另一個線程CPU。
  • stop方法需要很多時間來停止線程。

這只是一些事實,說明線程行為是如何不可預測的。 例如,首先嘗試啟動低優先級線程,我相信你會得到不同的結果。

另外,試試這個:

public class TestThread
{
    public static void main(String[] args){
        Thread r=Thread.currentThread();
        r.setPriority(Thread.MAX_PRIORITY);
        NewThread hi=new NewThread(Thread.MAX_PRIORITY);
        NewThread lo=new NewThread(Thread.MIN_PRIORITY);
        hi.start();
        lo.start();
        try{
            r.sleep(5000);
        }catch(InterruptedException e){
            System.out.println("caught");
        }
        hi.interrupt();
        lo.interrupt();

        System.out.println("hi="+hi.clicker);
        System.out.println("lo="+lo.clicker);
    }
}
class NewThread extends Thread{
    long clicker=0;

    NewThread(int p){
        setPriority(p);
    }
    public void run(){
        while(true){
            clicker++;
        }
    }
}

我確信刪除volatile變量並更改線程的停止方式將為您提供其他結果。

只為那些尋求更多解釋的人...以下是摘自“The Complete Reference,Java,Herbert Shieldt”

作為絕對價值,優先權毫無意義; 如果優先級較高的線程是唯一運行的線程,則它的運行速度不會低於優先級較低的線程。 相反,線程的優先級用於決定何時從一個正在運行的線程切換到下一個線程。 這稱為上下文切換。 確定上下文切換何時發生的規則很簡單:

  • 線程可以自願放棄控制。 這是通過在掛起的I / O上顯式生成,休眠或阻塞來完成的。 在這種情況下,將檢查所有其他線程,並為准備運行的最高優先級線程提供CPU。
  • 線程可以被更高優先級的線程搶占。 在這種情況下,不會產生處理器的低優先級線程只是被優先級更高的線程搶占 - 無論它在做什么。 基本上,只要優先級較高的線程想要運行,它就會運行。 這稱為搶先式多任務處理

線程本質上是不可預測的。 當高優先級線程由於某些原因而無法運行時,低優先級線程運行,而且當所有線程競爭CPU時,線程優先級不是很有意義。

但是當我執行上面的程序時,我得到了你書中提到的理想結果。

hi = 1707497920 lo=1699648942

hi = 1702682202 lo=1685457297

我在Windows 7上發現,如果我將線程數增加到實際存在系統資源爭奪點增加運行時間,那么優先級較高的線程會使點擊次數增加一個數量級。 如果不是這樣的話會很奇怪。 我認為您的測試用例在線程數量上都太小而無法使用他們必須要爭用的足夠資源,並且JVM綁定到本機線程的運行時間也是如此。

   public static void main(String[] args) {
        Thread r = Thread.currentThread();
        r.setPriority(Thread.MAX_PRIORITY);
        List<NewThread> hiThreads = new LinkedList<NewThread>();
        List<NewThread> lowThreads = new LinkedList<NewThread>();
        for (int i = 0; i < 10; i++) {
            NewThread hi = new NewThread(Thread.NORM_PRIORITY + 2);
            NewThread lo = new NewThread(Thread.NORM_PRIORITY - 2);
            hiThreads.add(hi);
            lowThreads.add(lo);
            hi.start();
            lo.start();
        }
        try {
            r.sleep(30000);
        } catch (InterruptedException e) {
            System.out.println("caught");
        }
        for (NewThread h : hiThreads) {
            h.stop();
        }
        for (NewThread l : lowThreads) {
            l.stop();
        }
        try {
            for (NewThread h : hiThreads) {
                h.t.join();
            }
            for (NewThread l : lowThreads) {
                l.t.join();
            }
        } catch (InterruptedException e) {
            System.out.println("cau1");
        }
        long hiClicker = 0l;
        for (NewThread h : hiThreads) {
            hiClicker += h.clicker;
        }
        long lowClicker = 0l;
        for (NewThread l : lowThreads) {
            lowClicker += l.clicker;
        }
        System.out.println("hi = " + hiClicker + " lo=" + lowClicker);
    }

我寫了一個小應用程序,看看Java線程是如何工作的:

https://github.com/vinhqdang/java-thread-example

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM