9.让线程放弃执行权
让线程放弃执行权
导言
如何让正在执行任务的线程放弃执行权,我们可以使用 thread类里面的yield的方法,该方法是一个静态方法,直接使用thread类名调用,它的作用是使当前线程放弃执行权,当前线程由执行状态变为就绪状态。
演示
下面来演示该方法,演示该方法需要用到两个任务,分别是赋值任务和打印任务。
赋值、任务的内容是定一个value属性,然后给value赋值,打印任务的内容是当value被赋值以后,打印value的值。
赋值任务
我们先来编写右边的赋值任务,定义一个静态属性value,初始值为0。
为了让放弃执行权效果更加明显,在给value赋值之前,我们让线程休眠三秒钟,最后我们给value赋值100,至此赋值任务编写完成。
package com.chenjie.executor.day09; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className Task (此处以class为例) * @date 2024/5/27 * @description TODO */ public class ValueTask implements Runnable{ public static Integer value=0; @Override public void run() { try { Thread.sleep(3000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("ValueTask执行了"); value=100; } }
打印任务
再来看看左边的打印任务,在打印任务中直接输出value的值,不过这样还没等到给value赋值,就直接输出了value的值。所以我们需要在value被赋值以前放弃执行权,使用while循环,判断value的值是否等于0。当y轴的值等于0时,直接使用thread类名调用yield的方法。 使当前现场放弃执行权,至此打印任务也编写完成。
package com.chenjie.executor.day09; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className PringTask (此处以class为例) * @date 2024/5/27 * @description TODO */ public class PrintTask implements Runnable{ @Override public void run() { while (ValueTask.value == 0){ Thread.yield(); } System.out.println("执行了value"+ValueTask.value); } }
执行
接下来分别执行这两个任务,首先将任务创建出来,然后创建两个线程,分别将这两个任务传递给两个线程,最后启动这两个线程。
package com.chenjie.executor.day09; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main { /** * 三秒后打印出结果,线程结束,主进程退出 * @param args */ public static void main(String[] args) { PrintTask pringTask = new PrintTask(); ValueTask valueTask=new ValueTask(); Thread thread=new Thread(pringTask); Thread thread1=new Thread(valueTask); thread.start(); thread1.start(); } }
结果
从运行结果来看,三秒之后value的值被打印了出来,符合预期。
ValueTask执行了 进程已结束,退出代码为 -1
不过打印任务中有一段代码存在争议,就是这段while代码能不能被以下两种情况替代?
while (ValueTask.value == 0){ Thread.yield(); }
第一种情况,循环题里面什么都不写,空转。
第二种情况,循环题里面写上continue。
其实这两种情况是一个意思,所以我们就拿第二种情况和源代码进行对比,我们来看看他们究竟有什么不同。
打印任务
package com.chenjie.executor.day09; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className PringTask (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Print1Task implements Runnable{ @Override public void run() { while (ValueTask.value == 0){ continue; } System.out.println("执行了value"+ValueTask.value); } }
package com.chenjie.executor.day09; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main1 { /** * 三秒后执行ValueTask执行了,但是printTask会一直空转,导致主线程不退出 * @param args */ public static void main(String[] args) { Print1Task pringTask = new Print1Task(); ValueTask valueTask=new ValueTask(); Thread thread=new Thread(pringTask); Thread thread1=new Thread(valueTask); thread.start(); thread1.start(); } }
执行结果
一直空转,线程不结束
再来看看yield的情况,打印任务的线程拿到了执行权,
但是 value的值一直为0。所以即使他拿到了知情权,也会放弃执行权。此时赋值任务的线程就会拿到执行权,他就会给value赋值,判断value是否等于0的时候,那么结果就会为false。那么此时呢我们的程序就顺利的执行完毕了。以上就是两段代码的区别。
总结
最后我们来总结一下本节的内容,本节介绍了thread类里面的yield的方法,它是一个静态方法,可以直接通过thread的类名调用。
作用是使当前线程放弃执行权,在实际开发中偶尔会用到它。
本文来自博客园,作者:小陈子博客,转载请注明原文链接:https://www.cnblogs.com/cj8357475/p/16085990.html