产量如何在这里起作用?

时间:2012-07-19 06:48:16

标签: java multithreading concurrency

方法Thread.yield

  

使当前正在执行的线程对象暂时暂停和   允许其他线程执行。

所以在下面的代码中:

public class Test implements Runnable {  

    private int stopValue;  

    public Fib(int stopValue){  
        this.stopValue = stopValue;  
    }  

    @Override  
    public void run() {  

        System.out.println("In test thread");  
        for(int i = 0; i < stopValue; i++){  
            c = i + 1;  
        }  

        System.out.println("Result = "+c);        
    }  

    public static void main(String[] args){  
        int defaultStop = 1024;  
        if(args.length > 0){   
            defaultStop = Integer.parseInt(args[0]);  
        }  
        Thread a = new Thread(new Fib(defaultStop));  
        System.out.println("In main");  
        a.setDaemon(true);  
        a.start();  
        Thread.yield();       
        System.out.println("Back in main");  
    }  

}

我希望我能看到:

  1. In main然后
  2. In test thread
  3. 其余的将是未定义的。但我不明白为什么有时候我只会看到: In mainBack in main而不是来自Test帖子的任何打印声明?

5 个答案:

答案 0 :(得分:4)

yield()是对已安排的操作系统的提示,但在调度方面没有提供任何保证。它并不总是停留很长时间。如果你重复调用它可能只需要几微秒。

启动一个线程需要时间,即使主线程暂停,也可能在后台线程启动之前完成。


如您所见,yield()暂停非常短暂。

long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
    Thread.yield();
long time = System.nanoTime() - start;
System.out.printf("Thread.yield() took an average of %,d ns.%n", time / runs);

打印

Thread.yield() took an average of 148 ns.

相比之下,System.nanoTime在我的机器上花费的时间更长。

long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
    System.nanoTime();
long time = System.nanoTime() - start;
System.out.printf("System.nanoTime() took an average of %,d ns.%n", time / runs);

打印

System.nanoTime() took an average of 656 ns.

两次都会因操作系统和操作系统以及机器而异。

答案 1 :(得分:2)

好吧,yield()可能什么都不做,因为就绪线程集小于核心数,在这种情况下两个线程都可以运行,而main()将继续运行到核心它在操作系统发出问题时(很可能是队列),调用其核心间驱动程序在另一个CPU核心上运行新线程。然后是与'System.out.println'的交互 - 一个可能用互斥锁保护的输出流调用。

我无法快速找到关于yield()在不同环境/ CPU / OS中实际做什么的任何可理解的解释 - 这是我从未使用过的原因之一。另一个是,无论它如何运作,我都无法想到它的任何用途。

答案 2 :(得分:0)

在线程有机会启动之前,主进程可能已经退出。无法保证Thread.yield()将强制线程在任何特定时间运行。如果线程没有启动,则setDaemon()将无效。

答案 3 :(得分:0)

尝试使用:

替换Thread.yield()
try {
        Thread.sleep(500);
    } catch (InterruptedException ex) {
        System.out.println(ex);
    }

答案 4 :(得分:0)

@ Peter的答案很好,但我想补充一些额外的信息作为答案。

首先,如其他地方所述,a.setDaemon(true)导致JVM 等待Thread a完成后退出。如果您真正的问题是如何确保Thread a在之前关闭关闭,那么删除setDaemon(true)可能是解决方案。当JVM退出时,可以杀死守护程序线程。将等待非守护程序线程。因此,main()方法可能会返回,主线程可能会退出,但您的Thread a仍会运行完毕。

Thread.yield()而言,如你所说,javadocs状态:

  

使当前正在执行的线程对象暂时暂停并允许其他线程执行。

然而,这有点误导。例如,如果您的架构上有2个线程正在运行且处理器上有2个或更多处理器,则yield()实际上将成为无操作。运行队列中没有其他线程正在等待处理器资源,因此主线程将被快速重新安排,并将以最小的暂停继续运行。

即使您在单个CPU系统上运行且Main执行yield(),您的Thread a也会执行System.out即IO。 IO可能会阻止导致线程执行立即切换回Main

当涉及到它时,只有在非常独特的情况下才需要使用yield()。我已经完成了多线程编程的很多,我从来没有使用它。相信JVM线程调度将在时间切片方面做“正确的事”,除非你有相反的探查器输出或专家建议,否则总是建议。