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的类名调用。 

作用是使当前线程放弃执行权,在实际开发中偶尔会用到它。 

 

posted @ 2022-04-26 22:29  小陈子博客  阅读(67)  评论(0编辑  收藏  举报