4

我是 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);
}

}

然而,根据书中的输出,具有高优先级的线程应该对变量 clicker 具有更高的值。但在我的情况下,较低优先级线程的变量 clicker 的值比较高优先级线程的值高得多。输出对我来说如下所示:-

hi = 2198713135 lo=2484053552

这是否意味着较低优先级的线程比较高优先级的线程获得更多的 CPU 时间......我错过了什么......在 ubuntu 和 win7 上的结果是相同的(较低优先级线程的更高点击器值)......

4

6 回答 6

3

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

另外,阅读这个关于协作与抢占线程的漂亮小段落:http: //www.cafeaulait.org/course/week11/32.html

于 2012-05-29T04:07:15.197 回答
3

正如 sul 所说,优先级更像是一个提示,而不是 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 变量并更改线程停止的方式会给您带来另一个结果。

于 2012-05-29T04:25:47.793 回答
1

仅针对那些寻求更多解释的人...以下是“完整参考,Java,Herbert Shieldt”的摘录

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

  • 线程可以自愿放弃控制。这是通过显式让步、休眠或阻塞挂起的 I/O 来完成的。在这种情况下,将检查所有其他线程,并为准备好运行的最高优先级线程分配 CPU。
  • 线程可以被更高优先级的线程抢占。在这种情况下,一个不让出处理器的低优先级线程简单地被一个高优先级线程抢占——不管它在做什么。基本上,只要更高优先级的线程想要运行,它就会运行。这称为抢先式多任务
于 2015-08-19T11:46:43.287 回答
0

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

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

hi = 1707497920 lo=1699648942

hi = 1702682202 lo=1685457297
于 2012-05-29T04:20:27.407 回答
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);
    }
于 2012-05-29T04:20:44.477 回答
0

我写了一个小应用程序来看看 Java 线程是如何工作的:

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

于 2014-11-27T10:35:37.603 回答