Java线程Thread.yeild方法解析

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

你可能感兴趣的:(Java线程Thread.yeild方法解析)