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

相关推荐
奋斗的小花生12 分钟前
c++ 多态性
开发语言·c++
魔道不误砍柴功14 分钟前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_23414 分钟前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨17 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程1 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk2 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*2 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue2 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man2 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉