“理解”;“优先权”;在java线程中

“理解”;“优先权”;在java线程中,java,multithreading,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

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

}

然而,根据书中的输出,具有高优先级的线程对于变量clicker应该具有更高的值。但在我的例子中,低优先级线程的变量clicker值比高优先级线程的值高得多。我的输出如下:-

hi = 2198713135 lo=2484053552

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

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

另外,请阅读这篇关于协作线程与抢占线程的精彩小文章:
线程本质上是不可预测的。低优先级线程在高优先级线程由于某些原因无法运行时运行,而且当所有线程都在争夺CPU时,线程优先级不是很有意义

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

hi = 1707497920 lo=1699648942

hi = 1702682202 lo=1685457297

我在Windows7上发现,如果我将线程数量增加到系统资源争夺的程度,并增加运行时间,那么优先级越高的线程点击次数就越多。如果不是这样,我会很好奇。我认为您的测试用例在线程数量和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);
    }
publicstaticvoidmain(字符串[]args){
线程r=Thread.currentThread();
r、 设置优先级(线程最大优先级);
List hiThreads=new LinkedList();
List lowThreads=newlinkedlist();
对于(int i=0;i<10;i++){
NewThread hi=新的NewThread(Thread.NORM_PRIORITY+2);
NewThread lo=新的NewThread(Thread.NORM_PRIORITY-2);
hiThreads.add(hi);
低线程。添加(lo);
嗨,开始();
lo.start();
}
试一试{
r、 睡眠(30000);
}捕捉(中断异常e){
系统输出打印项次(“捕获”);
}
for(NewThread h:hiThreads){
h、 停止();
}
用于(新线程l:低线程){
l、 停止();
}
试一试{
for(NewThread h:hiThreads){
h、 t.join();
}
用于(新线程l:低线程){
l、 t.join();
}
}捕捉(中断异常e){
系统输出打印项次(“cau1”);
}
长hiClicker=0升;
for(NewThread h:hiThreads){
hiClicker+=h.点击器;
}
长低响片=0升;
用于(新线程l:低线程){
lowClicker+=l.clicker;
}
System.out.println(“hi=“+hiClicker+”lo=“+lowClicker”);
}

正如sul所说,优先级与其说是JVM的契约,不如说是一种暗示。 在您的案例中,您的结果可以用几种理论来解释:

  • 第二个线程运行得更快,因为它利用了第一个线程编译的优点,并在第一个线程之后停止
  • while循环检查易失性变量的值迫使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变量并更改线程的停止方式将得到另一个结果。

我编写了一个小应用程序,以了解Java线程在以下情况下的工作方式:


仅适用于那些寻求更多解释的人。。。 以下是“完整参考,Java,Herbert Shieldt”的摘录

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

  • 线程可以自动放弃控制。这是通过显式 在挂起的I/O上让步、休眠或阻塞。在这种情况下,所有其他 检查线程,准备运行的最高优先级线程是 考虑到CPU
  • 线程可以被更高优先级的线程抢占。在这种情况下 不产生处理器的低优先级线程被简单地抢占 -无论它在做什么-由一个更高优先级的线程执行。基本上,尽快 当一个优先级较高的线程想要运行时,它会运行。这叫做先发制人 多任务

由于有两个线程,每个线程可能都有自己的CPU核心,而且从来没有任何涉及优先级的争用。我猜如果你有,比方说,10个线程,你可能会看到预期的行为。但即便如此,Java线程调度程序还是比抢占式更具协作性,因此如果没有显式的
yield()
调用,您可能仍然会得到“有趣的”结果。除此之外,您的问题“这是否意味着低优先级线程比高优先级线程获得更多的CPU时间…”的答案是。。不。@Heshan那是什么意思?好的,通过说“这不意味着低优先级线程比高优先级线程获得更多的CPU时间…”我假设你的意思是,在两个线程之间的竞争中,对于单个CPU的CPU时间,低优先级线程的CPU t
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++;
        }
    }
}