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 公众号:码路向前 。

相关推荐
Swift社区1 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht1 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht1 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20241 小时前
Swift 数组
开发语言
吾日三省吾码2 小时前
JVM 性能调优
java
stm 学习ing2 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc3 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐3 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi774 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器