Java线程Thread.yeild方法解析

作者: Ihesong | 来源:发表于2018-01-25 17:22 被阅读97次

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

        本文链接:https://www.haomeiwen.com/subject/yqzvaxtx.html