面试突击:Notify是随机唤醒吗?(面试秘籍:Notify机制是否随机唤醒线程?)
原创
一、引言
在Java多线程编程中,线程间的通信是一个重要的主题。notify()和wait()是Object类中的两个方法,它们常被用于线程间的协调和同步。面试中,常常会遇到涉及这两个方法的问题,其中一个常见的问题是:“notify是随机唤醒线程吗?”本文将围绕这个问题进行详细解答。
二、Notify和Wait机制简介
在Java中,每个对象都可以作为锁,线程可以通过调用对象的wait()方法进入等待状态,直到另一个线程调用该对象的notify()或notifyAll()方法。以下是这两个方法的基本使用:
public class MyObject {
public synchronized void waitMethod() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void notifyMethod() {
notify();
}
}
当一个线程调用对象的wait()方法时,该线程会释放对象的锁,并进入等待状态。当另一个线程调用该对象的notify()或notifyAll()方法时,等待的线程被唤醒,重新获得对象的锁,并继续执行。
三、Notify是否随机唤醒线程?
要回答这个问题,首先需要了解notify()和notifyAll()方法的区别:
- notify():唤醒在此对象上调用wait()方法的一个线程,具体唤醒哪个线程由JVM决定,具有一定的随机性。
- notifyAll():唤醒在此对象上调用wait()方法的所有线程,JVM会随机选择一个线程进行唤醒,但所有等待线程都有机会被唤醒。
由此可见,notify()方法确实有一定的随机性,但它并不是完全随机的。JVM会通过线程优先级、线程状态等因素来决定唤醒哪个线程。以下是一个单纯的示例,说明notify()的随机性:
public class NotifyExample {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 1 waiting...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 notified...");
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 waiting...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 notified...");
}
});
t1.start();
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
lock.notify();
}
}
}
在这个示例中,我们创建了两个线程t1和t2,它们都尝试在同一个锁对象上调用wait()方法。然后,我们在主线程中调用notify()方法。由于notify()的随机性,我们无法预测哪个线程会被唤醒。多次运行程序,大概会发现t1或t2被唤醒,导致是不确定的。
四、Notify机制的使用注意事项
在使用notify()和wait()方法时,需要注意以下几点:
- 确保调用wait()和notify()方法的代码块在同步块内执行。
- 在调用wait()方法前,必须先获得对象的锁。
- 在调用notify()方法时,也需要先获得对象的锁。
- 避免使用notify()方法唤醒不存在的等待线程。
- 尽量使用notifyAll()方法,而不是notify()方法,以避免随机性的问题。
五、总结
在面试中,当被问到“notify是随机唤醒线程吗?”时,我们可以回答:notify()方法确实有一定的随机性,它会通过JVM的调度策略来唤醒一个等待的线程。但并不是完全随机的,JVM会通过线程优先级、线程状态等因素来决定唤醒哪个线程。在实际编程中,我们应尽量使用notifyAll()方法,以避免随机性带来的问题。
六、延伸阅读
以下是一些涉及Java多线程编程和线程同步的延伸阅读资料,可以帮助你更深入地了解相关知识点:
- Java Object.wait() 方法文档
- Java Object.notify() 方法文档
- Java Object.notifyAll() 方法文档
- Java 并发编程:线程间的通信
- Java多线程之wait(),notify()和notifyAll()的使用