join(),sleep() 和 yeild() 方法的区别

目录

1、join() 方法:释放锁

2、sleep() 方法:不释放锁

3、yeild() 方法:不释放锁


1、join() 方法:释放锁

使用场景:

        等待调用 join() 方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。

        比如,主线程创建并启动子线程,如果自线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束。如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到 join() 方法。

        易混淆知识点:join() 方法为 Thread 类直接提供的方法,而 wait() 和 notify() Object类中的方法。

        查看 join() 方法源码,底层最终调用的还是 wait() 方法:

         join() 的主要作用是使当前主线程进行等待,另外也可以指定等待的具体时间:

public class JoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() { // 线程一
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 运行结束!");
            }
        }, "thread_1");
        t1.start();
        t1.join(); // 主线程会等待线程一运行结束
        // t1.join(1000);  // 超时将不再等待
        System.out.println("程序运行结束...");
    }
}

2、sleep() 方法:不释放锁

        调用 sleep() 方法会让当前线程从 Running 进入TIMED_WAITING 状态,不会释放对象锁

        睡眠结束后的线程未必会立刻得到执行,当 sleep() 传入参数为 0 时,和 yield 相同

        sleep() 方法可以被中断,其它线程可以使用 interrupt() 方法打断正在睡眠的线程,这时 sleep() 方法会抛出 InterruptedException,并且会清除中断标志

public class SleepTest {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000); // 会响应中断,并清除中断标记,不会睡眠 5s
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 执行结束!");
            }
        });
        t1.start();
        t1.interrupt(); // 打上中断标记
    }
}

        使用场景:当 A 需要等待 B 执行完,此时 A 设置 1 小时的等待时间(睡眠 1 小时),但是 B 只用了 30 分钟便执行完了,此时可以在 B 上执行 A 的中断方法,使 A 继续执行,因此,异常也是可以被利用的。

3、yeild() 方法:不释放锁

        yield() 会释放 CPU 资源,让当前线程从 Running 进入 Runnable 状态,让优先级更高 (至少是相同)的线程获得执行机会,不会释放对象锁;但 CPU 再次调度还可能调度到本线程

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

        官方不建议使用这个方法,因为线程切换CPU是有代价的

   /** <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     */
    public static native void yield();

        相关测试代码:

public class YieldTest extends Thread{
    // 对象锁
    public static Object lock = new Object();
    
    @Override
    public void run() {
        synchronized (lock) {// 加锁
            System.out.println(Thread.currentThread().getName() + "开始调用yield()方法");
            // 提醒1:打开关闭此注释查看输出效果,对比差异
            this.yield();
            // 提醒2:使用wait方法来做对比,查看释放锁与不释放锁的区别
//            try {
//                lock.wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(Thread.currentThread().getName() + " 执行结束");
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) { // 创建100个线程
            YieldTest test = new YieldTest();
            test.start();
        }
        // 提醒2:配合wait使用看效果
//        synchronized (lock) {
//            lock.notifyAll();
//        }
    }
}

        至此,三种方法的区别介绍完毕。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值