sleep(),wait(),yield()和join()方法的区别

本文详细介绍了Java中用于线程控制的四种方法:sleep()、wait()、yield()和join()。通过对比这些方法的特点,如是否释放锁标志、等待时间等,帮助读者理解它们在多线程编程中的应用场景。

sleep() 
  sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。 
   
wait() 
  wait()方法需要和notify()及notifyAll()两个方法一起介绍,这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用,也就是说,调用wait(),notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。注意,它们都是Object类的方法,而不是Thread类的方法。 
  wait()方法与sleep()方法的不同之处在于,wait()方法会释放对象的“锁标志”。当调用某一对象的wait()方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。当调用了某个对象的notifyAll()方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。 
  除了使用notify()和notifyAll()方法,还可以使用带毫秒参数的wait(long timeout)方法,效果是在延迟timeout毫秒后,被暂停的线程将被恢复到锁标志等待池。 
  此外,wait(),notify()及notifyAll()只能在synchronized语句中使用,但是如果使用的是ReenTrantLock实现同步,该如何达到这三个方法的效果呢?解决方法是使用ReenTrantLock.newCondition()获取一个Condition类对象,然后Condition的await(),signal()以及signalAll()分别对应上面的三个方法。

yield() 
  yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。

join() 
  join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行,例如:

package concurrent;

public class TestJoin {

    public static void main(String[] args) {
        Thread thread = new Thread(new JoinDemo());
        thread.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("主线程第" + i + "次执行!");
            if (i >= 2)
                try {
                    // t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}

class JoinDemo implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程1第" + i + "次执行!");
        }
    }
}

程序运行结果如下:

image_1b8jnbokkmua1q4n16kf2et1lbs9.png-140.6kB

### Java线程sleepwaitjoinyield方法区别及使用场景 #### 1. `sleep` 方法 `sleep` 是 `Thread` 类的静态方法,用于让当前正在执行的线程暂停一段时间。调用此方法后,线程将进入 **TIMED_WAITING** 状态,并在指定的时间结束后恢复执行[^1]。在此期间,线程不会释放它持有的锁。 - **特点**: - 静态方法,作用于当前线程。 - 不会释放锁。 - 线程状态为 **TIMED_WAITING**。 - 可能抛出 `InterruptedException` 异常。 - **代码示例**: ```java public class SleepExample { public static void main(String[] args) { Thread thread = new Thread(() -> { try { System.out.println("Thread is going to sleep..."); Thread.sleep(2000); // 当前线程休眠2秒 System.out.println("Thread woke up!"); } catch (InterruptedException e) { System.out.println("Thread was interrupted!"); } }); thread.start(); } } ``` - **使用场景**: - 模拟延迟操作。 - 控制线程执行间隔时间。 --- #### 2. `wait` 方法 `wait` 是 `Object` 类的方法,必须在同步代码块或方法中调用(即需要持有对象的锁)。调用此方法后,线程将释放锁并进入 **WAITING** 状态,直到其他线程调用该对象的 `notify` 或 `notifyAll` 方法唤醒它[^4]。 - **特点**: - 实例方法,作用于对象。 - 必须在同步上下文中调用。 - 释放锁。 - 线程状态为 **WAITING** 或 **TIMED_WAITING**(如果调用了 `wait(long timeout)`)。 - 可能抛出 `IllegalMonitorStateException` `InterruptedException` 异常。 - **代码示例**: ```java public class WaitExample { private static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { new Thread(() -> { synchronized (lock) { try { System.out.println("Thread is waiting..."); lock.wait(); // 当前线程等待 System.out.println("Thread was notified!"); } catch (InterruptedException e) { System.out.println("Thread was interrupted!"); } } }).start(); Thread.sleep(1000); synchronized (lock) { lock.notify(); // 唤醒等待中的线程 } } } ``` - **使用场景**: - 实现生产者-消费者模式。 - 等待特定条件满足后再继续执行。 --- #### 3. `join` 方法 `join` 是 `Thread` 类的方法,用于等待调用该方法线程执行完毕。调用 `join` 后,当前线程会阻塞,直到目标线程结束运行[^2]。在此期间,线程状态为 **WAITING** 或 **TIMED_WAITING**(如果调用了带超时参数的版本)。 - **特点**: - 实例方法,作用于线程。 - 会释放锁。 - 线程状态为 **WAITING** 或 **TIMED_WAITING**。 - 可能抛出 `InterruptedException` 异常。 - **代码示例**: ```java public class JoinExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Child thread: " + i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); thread.join(); // 主线程等待子线程执行完毕 System.out.println("Main thread: Child thread has finished."); } } ``` - **使用场景**: - 确保某个线程的任务完成后再继续执行后续逻辑。 - 实现线程间的顺序依赖。 --- #### 4. `yield` 方法 `yield` 是 `Thread` 类的静态方法,用于建议当前线程让出 CPU 执行权,但不保证一定会让出[^5]。调用此方法后,线程将回到 **RUNNABLE** 状态,由线程调度器决定是否重新分配执行权。 - **特点**: - 静态方法,作用于当前线程。 - 不会释放锁。 - 线程状态始终为 **RUNNABLE**。 - 让出 CPU 执行权是建议性的,可能无效。 - **代码示例**: ```java public class YieldExample { public static void main(String[] args) { Thread thread = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Thread: " + i); if (i % 2 == 0) { Thread.yield(); // 建议当前线程让出CPU执行权 } } }); thread.start(); } } ``` - **使用场景**: - 调整线程优先级,优化资源分配。 - 提高多线程程序的公平性。 --- ### 方法对比总结 | 方法 | 类型 | 是否释放锁 | 线程状态 | 使用场景 | |--------|------------|------------|-----------------------|--------------------------------------------------------------------------| | `sleep` | 静态方法 | 否 | TIMED_WAITING | 模拟延迟、控制线程执行间隔 | | `wait` | 实例方法 | 是 | WAITING/TIMED_WAITING | 生产者-消费者模式、等待条件满足 | | `join` | 实例方法 | 是 | WAITING/TIMED_WAITING | 确保线程顺序执行、等待其他线程完成任务 | | `yield` | 静态方法 | 否 | RUNNABLE | 调整线程优先级、优化资源分配 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值