HOME/Articles/

Java多线程之join、yield、sleep

Article Outline

Java多线程之join、yield、sleep

yield方法

这个方法感觉平时是用的最少的

1、调用yield会让当前线程从Running进入Runnable状态,然后调度执行其他同优先级的线程,如果此时没有同优先级的线程,那么不能保证让当前线程暂停的效果。

2、具体的实现依赖于操作系统的任务调度器。

这里提到的 Running就是运行中的状态,而Runnable 对应了操作系统的就绪状态。

sleep方法

1、调用sleep方法会让当前线程从Running进入Timed_waiting状态

2、其他线程可以使用interrupt()方法打断正在睡眠的线程,此时sleep方法会抛出interredException

3、睡眠结束后的线程未必会立刻执行

public class Thread1 {

    public Logger LOGGER = LoggerFactory.getLogger(Thread1.class);

    @Test
    public void test() {
        Thread thread = new Thread("t1") {
            public void run() {
                try {
                    LOGGER.info("begin sleep");
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    LOGGER.info("wake up"+e.getMessage());
                    e.printStackTrace();
                }
            }
        };
        thread.start();
        try {
            Thread.sleep(500);
            LOGGER.info("唤醒");
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}
7:14:31.063  INFO 12708 --- [             t1] com.example.demo.Thread1                 : begin sleep
2021-01-08 17:14:31.575  INFO 12708 --- [           main] com.example.demo.Thread1                 : 唤醒
2021-01-08 17:14:31.576  INFO 12708 --- [             t1] com.example.demo.Thread1                 : wake upsleep interrupted
java.lang.InterruptedException: sleep interrupted
    at java.base/java.lang.Thread.sleep(Native Method)
    at com.example.demo.Thread1$1.run(Thread1.java:22)

sleep的另类用法!!!!!!

利用sleep防止CPU占用100%

sleep 在没有利用cpu来计算时,不要让while(ture)一直占用cpu,这时可以使用yield或者sleep来让出cpu的使用权给其他程序

注意,sleep的时间不用太大,只要有sleep就ok,因为sleep会使程序让出CPU时间,给其他程序使用,尤其单核cpu的情况下,不加sleep会使cpu的占用率达到90%+

可以使用wait或者条件变量达到类似的效果

不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景

sleep适用于无需锁同步的场景。

join方法

join方法用来等待线程执行结束

例子如下:

public class Test2 {
    Logger LOGGER = LoggerFactory.getLogger(Test2.class);
    static int r = 0;

    @Test
    public void test()  {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    LOGGER.info("begin");
                    TimeUnit.SECONDS.sleep(1);
                    r = 10;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        t1.start();

        LOGGER.info("r= " + r);
    }
}

2021-01-08 23:53:35.591  INFO 8212 --- [Thread-1] com.example.demo.Test2: begin
2021-01-08 23:53:35.592  INFO 8212 --- [main] com.example.demo.Test2: r= 0



 /*可以看到,输出的结果并不是r=10,因为线程休眠了1秒,而主线程在启动了t1线程后,没有等待1秒,直接继续向下执行了输出操作,解决的方案就是,让主线程输出前,等待t1线程执行结束。
 */
       t1.start();
        t1.join();
        LOGGER.info("r= " + r);
    }

在添加join之后,输出结果如下:

2021-01-09 00:03:45.855  INFO 9652 --- [Thread-1] com.example.demo.Test2                   : begin
2021-01-09 00:03:46.871  INFO 9652 --- [main] com.example.demo.Test2                   : r= 10

下一个问题

因为join可以设置等待时间,那么,如果join的时间大于实际线程执行的时间会怎么样呢?

    t1.start();
        t1.join(3000);
        LOGGER.info("r= " + r);
    }

这里把时间等待3秒,而实际线程1秒就可以完成。

运行结果如下:

2021-01-09 00:18:20.047  INFO 8968 --- [Thread-1] com.example.demo.Test2                :begin
2021-01-09 00:18:21.053  INFO 8968 --- [main] com.example.demo.Test2                   :r= 10

可以看到,代码会以线程和等待较短的时间为准。