2024年150道高频Java面试题(三十一)

61. sleep() 和 wait() 有什么区别?

sleep()wait() 方法在Java中被广泛用于线程控制,它们都可以让线程暂停执行一段时间,但它们之间存在一些重要的区别:

  1. 所属类
    • sleep()Thread 类的静态方法。
    • wait()Object 类的方法。
  2. 使用范围
    • sleep() 可以在任何地方使用,因为它属于 Thread 类。
    • wait() 必须在同步上下文中调用,即必须在获取了对象锁的代码块中使用,通常用在对象的同步方法或同步代码块中。
  3. 释放锁
    • sleep() 不会释放当前线程所持有的锁资源。
    • wait() 会立即释放当前线程持有的锁资源,直到另一个线程调用同一个对象的 notify()notifyAll() 方法来唤醒它。
  4. 精度
    • sleep() 方法通常用于短时间等待,它能够指定具体的等待时间(毫秒或纳秒),并且能够较为准确地控制唤醒时间。
    • wait() 方法没有参数,它通常用于线程间的通信,等待其他线程的通知,等待的时间是不确定的。
  5. 方法调用
    • 调用 sleep() 方法不需要当前线程拥有任何锁。
    • 调用 wait() 方法必须在拥有对象的锁的情况下进行。
  6. 唤醒方式
    • sleep() 方法到达指定时间后自动唤醒。
    • wait() 方法需要其他线程调用对象的 notify()notifyAll() 来唤醒。

以下是 sleep()wait() 的代码示例:

java 复制代码
// sleep() 方法示例
Thread thread = new Thread(() -> {
    try {
        Thread.sleep(1000); // 休眠1秒
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("线程被唤醒");
});

// wait() 方法示例
Object lock = new Object();
new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait(); // 等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程通过notify()被唤醒");
    }
}).start();

// 在另一个线程中唤醒wait()的线程
new Thread(() -> {
    synchronized (lock) {
        lock.notify(); // 唤醒等待的线程
    }
}).start();

在使用 wait()notify() 时,通常需要紧密协调以确保线程安全,而 sleep() 更适合于简单的定时等待场景。

62. notify() 和 notifyAll()有什么区别?

notify()notifyAll() 是Java中用于线程同步的Object类的方法,它们用于唤醒等待同一共享资源的线程。

notify() 方法:

  • 它会随机选择一个在对象监视器上等待的线程,并通知该线程,使其从等待状态进入可运行状态。
  • 选择哪个线程是由JVM决定的,并且是不可预测的。
  • 如果没有线程在等待,notify()调用不会有任何效果。
  • 在被通知的线程重新获得对共享资源的访问权限并退出同步块之前,其他线程仍然处于阻塞状态。

notifyAll() 方法:

  • 它会通知所有在该对象监视器上等待的线程,使它们从等待状态进入可运行状态。
  • 这样,所有等待的线程都有机会获取共享资源,并继续执行。
  • 如果没有线程在等待,notifyAll()调用同样不会有任何效果。

以下是这两个方法的使用场景和区别的总结:

对比项 notify() notifyAll()
通知的线程数量 通知单个线程 通知所有等待的线程
使用场景 当只有一个线程需要被唤醒时,以避免不必要的上下文切换 当多个线程都在等待同一条件时,需要唤醒所有线程
效率 可能更高效,因为它不需要唤醒所有线程 可能导致上下文切换次数增多,但确保了所有等待线程都有机会运行
死锁风险 如果选择错误的线程可能会增加死锁的风险 适用于多个线程需要被唤醒的场景,降低了死锁的风险

以下是这两个方法的一个简单代码示例:

java 复制代码
public class SharedObject {
    public synchronized void doSomething() {
        // 假设这里是需要共享资源的代码块
        // ...
        // 通知正在等待的线程(单个或所有)
        this.notify(); // 或者 this.notifyAll();
    }
}

public class ThreadA extends Thread {
    private SharedObject sharedObject;
    
    public ThreadA(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }
    
    @Override
    public void run() {
        synchronized(sharedObject) {
            try {
                // 等待,直到被notify()或notifyAll()唤醒
                sharedObject.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 执行共享资源操作
            sharedObject.doSomething();
        }
    }
}

在以上代码中,notify()notifyAll()可以在doSomething()方法中互换使用,但它们的效果和适用场景会有明显的不同。

有帮助请点赞收藏呀~

领【150 道精选 Java 高频面试题】请 go 公众号:码路向前 。

相关推荐
网安-轩逸1 小时前
IPv4地址表示法详解
开发语言·php
陌上花开࿈3 小时前
调用第三方接口
java
Aileen_0v03 小时前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
西猫雷婶4 小时前
python学opencv|读取图像(十九)使用cv2.rectangle()绘制矩形
开发语言·python·opencv
桂月二二5 小时前
Java与容器化:如何使用Docker和Kubernetes优化Java应用的部署
java·docker·kubernetes
liuxin334455665 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
码农W5 小时前
QT--静态插件、动态插件
开发语言·qt
ke_wu5 小时前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
小马爱打代码5 小时前
设计模式详解(建造者模式)
java·设计模式·建造者模式
code04号5 小时前
python脚本:批量提取excel数据
开发语言·python·excel