Java多线程之wait(), notify(), notifyAll()的详解分析
在Java多线程编程中,wait(), notify(), notifyAll()是非常重要的方法。这三个方法都是用于线程间的协作,可以让线程在合适的时候等待或唤醒其他线程,实现高效的资源共享和数据交换。本文将详细介绍wait(), notify(), notifyAll()的概念、作用和使用方法,并提供两个示例说明。
wait()
wait()方法是Object类中定义的方法,用于让当前线程进入等待状态,直到收到其他线程的notify()或notifyAll()通知后再继续执行。wait()方法通常和synchronized关键字一起使用,以保证同步和互斥的效果。当线程执行wait()方法时,它会释放占有的锁对象,让其他线程可以访问共享资源。当其他线程改变资源状态并调用notify()或notifyAll()方法时,处于等待状态的线程将被唤醒,重新竞争锁,并继续执行。
wait()方法有三个重载方法:
- wait(): 让当前线程无限期等待,直到其他线程调用notify()或notifyAll()方法唤醒它。
- wait(long timeout): 让当前线程等待一定时间,直到超时或收到其他线程的notify()或notifyAll()通知唤醒它。
- wait(long timeout, int nanos): 和wait(long timeout)类似,只是更精细地定义了等待时间。
wait()方法的使用常见模式如下所示:
synchronized (object) {
while (condition does not hold) {
object.wait();
}
// take action based on condition holding
}
其中,object是一个共享对象,condition是一个布尔表达式,用于描述等待条件是否成立。执行wait()方法时,先获取Object对象的锁对象,然后判断条件是否成立。如果不成立,则调用wait()方法让当前线程进入等待状态,并释放Object的锁对象,让其他线程可以获得该锁对象并修改共享变量。当其他线程更新共享变量并符合等待条件时,调用notify()或notifyAll()方法唤醒处于等待状态的线程,并重新竞争Object的锁对象,继续执行。
notify()
notify()方法也是Object类中定义的方法,用于唤醒处于wait()方法等待状态的一个线程,并通知它有可能可以重新竞争锁对象。notify()方法一般用于在同步代码块内部,唤醒等待线程并让它重新竞争所属对象的锁。如果有多个等待线程,notify()方法只随机唤醒其中的一个线程,并不保证唤醒的线程是最优先等待的线程。
notify()方法一般的使用模式如下:
synchronized (object) {
// make some change to shared variables
object.notify();
}
其中,object是共享对象,调用notify()方法表示唤醒了处于object上wait()状态下的某一个线程并让它重新竞争锁。
notifyAll()
notifyAll()方法和notify()方法类似,也是用于唤醒处于wait()状态的线程,并让它们重新竞争锁对象。不同点是,notifyAll()方法会唤醒所有处于当前对象等待队列上的线程,让它们可以重新竞争所属对象的锁。如果多个线程等待同一个共享对象,notifyAll()方法将唤醒所有线程,并让它们重新竞争对象锁。
notifyAll()方法一般的使用模式如下:
synchronized (object) {
// make some change to shared variables
object.notifyAll();
}
示例说明一
代码如下:
public class WaitNotifyExample {
public static void main(String[] args) {
final Processor processor = new Processor();
Thread producerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
processor.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
processor.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producerThread.start();
consumerThread.start();
}
}
class Processor {
public void produce() throws InterruptedException {
synchronized (this) {
System.out.println("Producer thread running...");
wait();
System.out.println("Producer thread resumed.");
}
}
public void consume() throws InterruptedException {
Thread.sleep(1000); // 模拟其他耗时操作
Scanner scanner = new Scanner(System.in);
synchronized (this) {
System.out.println("Waiting for return key pressed...");
scanner.nextLine();
notify();
Thread.sleep(5000); // 模拟其他耗时操作
}
}
}
在上面的代码中,我们定义了一个Processor类,它有两个方法produce()和consume()。produce()方法会让线程进入等待状态,并等待consume()方法的唤醒通知。consume()方法则会让线程进行一些耗时操作(模拟其他线程访问共享变量并对其进行修改),然后等待用户的键盘输入。当用户按下回车键时,consume()方法调用notify()方法唤醒处于等待状态的线程并输出"notify() called",然后进行一些其他的耗时操作(模拟其他线程访问共享变量并对其进行修改)。在主线程中,我们创建了两个线程,分别运行producerThread和consumerThread,并启动它们。运行程序后,输出如下:
Producer thread running...
Waiting for return key pressed...
notify() called
Producer thread resumed.
我们可以看到,producerThread线程进入了等待状态,直到consumerThread线程调用notify()方法,唤醒了producerThread线程并输出"notify() called",producerThread线程才停止等待,继续执行。
示例说明二
代码如下:
public class SecondWaitNotifyExample {
private static Object lock = new Object();
private static void log(String msg) {
System.out.println(Thread.currentThread().getName() + ": " + msg);
}
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
log("Thread-1 waiting...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log("Thread-1 notified.");
}
}
}, "Thread-1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
log("Thread-2 waiting...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log("Thread-2 notified.");
}
}
}, "Thread-2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
log("Thread-3 notifying...");
lock.notifyAll();
}
}
}, "Thread-3");
thread1.start();
thread2.start();
try {
Thread.sleep(1000); // 暂停1秒,确保线程1和线程2都处于等待状态
} catch (InterruptedException e) {
e.printStackTrace();
}
thread3.start();
}
}
在上面的代码中,我们定义了三个线程,分别为Thread-1、Thread-2和Thread-3。Thread-1和Thread-2作为等待线程,在lock对象上等待被其他线程唤醒;Thread-3作为通知线程,调用lock对象的notifyAll()方法唤醒等待在lock对象上的所有线程。在主线程中,我们启动线程1和线程2,并暂停1秒等待线程1和线程2都处于等待状态,然后启动线程3。
运行程序后,输出如下:
Thread-1: Thread-1 waiting...
Thread-2: Thread-2 waiting...
Thread-3: Thread-3 notifying...
Thread-1: Thread-1 notified.
Thread-2: Thread-2 notified.
我们可以看到,在Thread-3调用lock对象的notifyAll()方法后,两个等待线程Thread-1和Thread-2都被唤醒,并输出对应的日志。这是因为notifyAll()方法唤醒了所有等待线程,让它们重新竞争lock对象的锁。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java多线程之wait(),notify(),notifyAll()的详解分析 - Python技术站