(一)java yield()方法注释:
/*** A hint to the scheduler that the current thread is willing to yield* its current use of a processor. The scheduler is free to ignore this* hint.** <p> Yield is a heuristic attempt to improve relative progression* between threads that would otherwise over-utilise a CPU. Its use* should be combined with detailed profiling and benchmarking to* ensure that it actually has the desired effect.** <p> It is rarely appropriate to use this method. It may be useful* for debugging or testing purposes, where it may help to reproduce* bugs due to race conditions. It may also be useful when designing* concurrency control constructs such as the ones in the* {@link java.util.concurrent.locks} package.*/
大致意思:yield()方法会通知线程调度器放弃对处理器的占用,但调度器可以忽视这个通知。yield()方法主要是为了保障线程间调度的连续性,防止某个线程一直长时间占用cpu资源。但是他的使用应该基于详细的分析和测试。这个方法一般不推荐使用,它主要用于debug和测试程序,用来减少bug以及对于并发程序结构的设计。
(二)方法理解:
Thread.yield()翻译成中文就是让步的意思,根据语义理解就是线程让出当前时间片给其他线程执行。这个函数在JSL中未给出明确的语义,就是没有要求具体如何实现,这取决于各个不同jvm的具体实现。部分jvm在执行这个函数时可能什么都不做,但是大部分jvm的实现都是:将线程从running状态转为runnable状态,然后放入同优先级等待队列的末尾,等待前面所有相同优先级的线程调度完成后才可能再度获得执行机会。不过当同优先级队列中刚好只剩这个线程时,那么这个线程可能很快就又获得了cpu时间片。我们常用的HotSpot默认采用的是第二种方式。
我们再看个小例子:
public class YieldTest extends Thread {public YieldTest(String name) {super(name);}@Overridepublic void run() {for (int i = 1; i <= 1000; i++) {System.out.println("" + this.getName() + "-----" + i);if (i == 30 || i == 100 || i == 500 || i == 700 || i == 800 || i == 900) {Thread.yield();}}}public static void main(String[] args) {YieldTest yt1 = new YieldTest("张三");YieldTest yt2 = new YieldTest("李四");yt1.start();yt2.start();}
}
运行结果:
我们会惊奇的发现:调用Thread.yield()后线程并不一定会立刻停止执行,i == 100时调用Thread.yield()后线程没有立刻放弃cpu时间片,李四这个无耻之徒还在执行呢!
这个主要是因为张三从runnable状态切换到running状态是需要一些准备的,这个需要耗费一些时间。系统为了避免cpu资源的浪费还会让李四在执行一小段时间。不过调度器后面一定会让张三执行下的,面子工程必须得做的。所以就如同yield()方法注释中说的,业务代码使用这个函数需慎重。