Java线程Thread的yeild方法可能在日常使用中比较少出现,那它是做什么用的,我们先查查官方文档解释。
yield
public static void yield()
Causes the currently executing thread object to temporarily pause and allow other threads to execute.
看原版官方文档可以避免出现歧义,我的理解是
造成当前正在执行的线程对象临时性的暂停,和允许其他线程去执行
也就是说,调用了yield方法之后,当前线程会临时性的暂停一下,然后其他线程有机会去执行任务。那么实际情况是怎么样,我们用例子来测试一下。
public class YieldTest{
private static final int DEST_NUM = 50;
public static void main(String[] args) {
new YieldTest();
}
public YieldTest(){
ThreadDemo yt1 = new ThreadDemo("张三");
ThreadDemo yt2 = new ThreadDemo("李四");
ThreadDemo yt3 = new ThreadDemo("王五");
//yt1.setPriority(10);
//yt1.setPriority(5);
//yt3.setPriority(1);
yt1.start();
yt2.start();
yt3.start();
}
public class ThreadDemo extends Thread{
public ThreadDemo(String name){
setName(name);
}
@Override public void run() {
for (int i = 1; i <= DEST_NUM; i++) {
// 当i为30时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)
if (i % 5 == 0) {
System.out.println("" + this.getName() + "-----" + i + " yeild一下");
yield();
}else{
System.out.println("" + this.getName() + "-----" + i);
}
}
}
}
}
上面的例子是,开启张三,李四,王五三个线程分别打印从1到50的数字,每当打印的数字是5的倍数时(比如打印5,10,15等),就yield一下。那么我们看看运行之后的结果是怎么样的。
张三-----1
王五-----1
李四-----1
王五-----2
王五-----3
王五-----4
张三-----2
张三-----3
王五-----5 yeild一下
李四-----2
李四-----3
李四-----4
李四-----5 yeild一下 /////////
李四-----6
李四-----7
李四-----8
王五-----6
王五-----7
王五-----8
王五-----9
王五-----10 yeild一下
张三-----4
张三-----5 yeild一下 //////////
张三-----6
张三-----7
张三-----8
张三-----9
张三-----10 yeild一下 /////////
张三-----11
张三-----12
张三-----13
张三-----14
张三-----15 yeild一下 /////////
张三-----16
张三-----17
张三-----18
张三-----19
//其余的省略
。。。
可以看到这次张三虽然多次yeild了,但是依然继续执行了。我们再运行一次看看
张三-----1
张三-----2
张三-----3
张三-----4
张三-----5 yeild一下
李四-----1
李四-----2
李四-----3
李四-----4
李四-----5 yeild一下
王五-----1
王五-----2
王五-----3
王五-----4
王五-----5 yeild一下
张三-----6
张三-----7
张三-----8
张三-----9
张三-----10 yeild一下
李四-----6
李四-----7
李四-----8
李四-----9
李四-----10 yeild一下
王五-----6
王五-----7
王五-----8
王五-----9
王五-----10 yeild一下
张三-----11
张三-----12
张三-----13
张三-----14
张三-----15 yeild一下
李四-----11
李四-----12
李四-----13
李四-----14
李四-----15 yeild一下
王五-----11
王五-----12
王五-----13
王五-----14
王五-----15 yeild一下
张三-----16
张三-----17
张三-----18
张三-----19
张三-----20 yeild一下
李四-----16
李四-----17
//其余的省略
。。。
yield原理
发现这一次,每次调用了yeild之后,它们都没有紧接着执行了。这是为什么呢,难道yield没有用处了吗?
其实上面出现的不确定结果,是因为多核CPU执行的关系,一个线程调用了yield方法之后,确实会让出当前使用的CPU,让自己从【运行态】变为【就绪态】。
- 当运行环境是单核CPU的时候。如果其他线程已经处于就绪态,正在等待CPU时间片时,这时有线程yield让出了CPU时间片,它们中的一个就会先有可能分配到CPU时间片,进而进入【运行态】,执行线程内容。
- 而当运行环境是多核CPU的话。也许上面的三个线程都是同时处于【运行态】正在执行,那个一个线程yiedl之后,短暂的让出了它的CPU,而此时又没有线程跟它抢CPU(因为其他两个都在运行着),所以它可能又获得了CPU时间片又去执行了。所以针对多核CPU环境的话,测试结果并没有明显的规律。
yield错误观点纠正
网上有说“yield之后,只有同优先级的线程能执行,低优先级的线程无法获得执行”,这是错误的观点,Java文档并没有这种说,Java虚拟机也并没有这种限制。会大概率出现这种情况主要是因为yield之后,高优先级的线程会更容易得到调度优先得到CPU时间片执行,低优先级自然被执行的概率就更少了,但是并不是说低优先级线程就无法被执行。可以把上面代码的优先级设置部分注释去掉,自己亲自运行看看结果,别被误导了。
yield的使用场景
yield的作用就是暂时让出使用着的CPU,这样其他【就绪态】的线程就有机会占用这个CPU去执行。所以yield的使用场景多在,当前线程在进行耗时性的操作时(如IO操作),并且因为它的优先级较高,导致一些优先级较低的线程被分配的时间片更少,这样优先级低的线程就要等待更长时间才能完成操作,那么这时适当地调用几次yield方法让出CPU,让优先级低的线程多得到执行,这样才能高效的实现程序执行和响应。
测试例子查看 我的GitHub--JavaTest