1

方法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

其余的将是未定义的。但我不明白为什么有时我只看到: In mainBack in main不是Test线程中的任何打印语句?

4

5 回答 5

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.

这两个时间都会因操作系统和机器而异。

于 2012-07-19T06:52:12.243 回答
2

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

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

于 2012-07-19T07:28:22.243 回答
0

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

于 2012-07-19T06:52:28.190 回答
0

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

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

Thread.yield()正如您所提到的,就 javadocs而言:

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

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

即使您在单个 CPU 系统上运行并且Main确实如此yield(),您也会Thread a去做一个System.outIO。IO 可能会阻塞导致线程执行立即切换回Main

归根结底,只有在非常独特的情况下才yield()需要使用。我做过很多多线程编程,但我从未使用过它。除非您有分析器输出或相反的专家建议,否则始终建议您相信 JVM 线程调度将在时间切片方面“做正确的事情”。

于 2012-07-19T14:20:19.097 回答
0

尝试将 Thread.yield() 替换为:

try {
        Thread.sleep(500);
    } catch (InterruptedException ex) {
        System.out.println(ex);
    }
于 2012-07-19T07:29:00.113 回答