61. sleep() 和 wait() 有什么区别?
sleep()
和 wait()
方法在Java中被广泛用于线程控制,它们都可以让线程暂停执行一段时间,但它们之间存在一些重要的区别:
- 所属类 :
sleep()
是Thread
类的静态方法。wait()
是Object
类的方法。
- 使用范围 :
sleep()
可以在任何地方使用,因为它属于Thread
类。wait()
必须在同步上下文中调用,即必须在获取了对象锁的代码块中使用,通常用在对象的同步方法或同步代码块中。
- 释放锁 :
sleep()
不会释放当前线程所持有的锁资源。wait()
会立即释放当前线程持有的锁资源,直到另一个线程调用同一个对象的notify()
或notifyAll()
方法来唤醒它。
- 精度 :
sleep()
方法通常用于短时间等待,它能够指定具体的等待时间(毫秒或纳秒),并且能够较为准确地控制唤醒时间。wait()
方法没有参数,它通常用于线程间的通信,等待其他线程的通知,等待的时间是不确定的。
- 方法调用 :
- 调用
sleep()
方法不需要当前线程拥有任何锁。 - 调用
wait()
方法必须在拥有对象的锁的情况下进行。
- 调用
- 唤醒方式 :
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 公众号:码路向前 。