理解java线程中的“优先级”

时间:2012-05-29 03:48:40

标签: java multithreading

我是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上的结果是相同的(较低优先级线程的较高的点击者值)。 ..

6 个答案:

答案 0 :(得分:3)

Java中的线程优先级不保证预期的行为。这就像是对JVM的暗示。实际行为取决于底层操作系统。

另外,请阅读有关合作与先发制人线程的这个不错的小段落: http://www.cafeaulait.org/course/week11/32.html

答案 1 :(得分:2)

正如苏尔所说,优先权更多的是提示而不是与JVM的合同。 在您的情况下,您的结果可以用几种理论来解释:

  • 第二个线程运行得更快,因为它获得了第一个线程编译的好处,并在第一个线程之后停止。
  • while循环检查volatile变量的值的事实迫使jvm实现该值,在此期间可以为另一个线程提供CPU。
  • 停止方法需要很长时间才能停止线程。

这只是一些事实,说明线程行为是如何不可预测的。例如,首先尝试启动低优先级线程,我相信你会得到不同的结果。

另外,试试这个:

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变量并更改线程停止的方式会给你另一个结果。

答案 2 :(得分:1)

只为那些寻求更多解释的人... 以下是“The Complete Reference,Java,Herbert Shieldt”的摘录

  

作为绝对值,优先权毫无意义;如果优先级较高的线程是唯一运行的线程,则它的运行速度不会低于优先级较低的线程。 相反,线程的优先级用于决定何时从一个正在运行的线程切换到下一个线程。这称为上下文切换。确定上下文切换何时发生的规则很简单:

     
      
  • 线程可以自愿放弃控制权。这是明确地完成的   在挂起的I / O上产生,休眠或阻塞。在这种情况下,所有其他   检查线程,并准备运行的最高优先级线程是   鉴于CPU。
  •   
  • 线程可以被更高优先级的线程抢占。在这种情况下,一个   不会产生处理器的低优先级线程被简单地抢占    - 无论它做什么 - 通过更高优先级的线程。基本上,尽快   作为优先级较高的线程想要运行,它确实如此。这被称为先发制人   多任务
  •   

答案 3 :(得分:0)

线程本质上是不可预测的。当高优先级线程由于某些原因而无法运行时,低优先级线程运行,而且当所有线程竞争CPU时,线程优先级不是很有意义。

但是当我执行上面的程序时,我得到了你书中提到的理想结果。

hi = 1707497920 lo=1699648942

hi = 1702682202 lo=1685457297

答案 4 :(得分:0)

我发现在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);
    }

答案 5 :(得分:0)

我编写了一个小应用程序,以了解Java线程的工作原理:

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