Java中的wait方法是多線程中常用的一種同步方式,它的作用是讓線程進入等待狀態,直到其他線程調用notify或者notifyAll方法喚醒它。在控制線程同步方面,wait方法的使用是非常必要的。
一、wait方法基本用法
wait方法用於等待其他線程的通知,並且會釋放鎖資源。下面是wait方法的基本用法:
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
在上述代碼中,首先獲取對象鎖,然後調用wait方法使當前線程進入等待狀態,直到其他線程調用notify或者notifyAll方法喚醒它。當線程進入等待狀態後,所佔用的鎖資源會被釋放出來,其他線程就可以獲取這個鎖。
在wait方法上,也可以設置等待的最大時間,如果在等待時間內沒有被喚醒,線程就會自動蘇醒。具體的代碼如下:
try {
synchronized (this) {
wait(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
在上述代碼中,等待時間為1000毫秒,如果在此時間內沒有被喚醒,線程就會自動蘇醒。
二、notify和notifyAll方法
notify方法用於喚醒一個等待中的線程,而notifyAll方法用於喚醒所有等待中的線程。
以下是notify和notifyAll方法的用法示例:
try {
synchronized (this) {
notify();
// 或者notifyAll();
}
} catch (Exception e) {
e.printStackTrace();
}
三、wait和notify的經典應用場景
1. 生產者和消費者問題
生產者和消費者問題是多線程中常見的一種同步問題。生產者和消費者共同使用一個隊列,生產者向隊列中生產數據,消費者從隊列中取出數據。如果隊列已經滿了,生產者就需要等待消費者取走數據以後才能繼續生產,如果隊列已經空了,消費者就需要等待生產者生產數據以後才能繼續消費。
下面是使用wait和notify來解決生產者和消費者問題的經典實現:
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer {
private final Queue<Object> queue = new LinkedList<>();
private final int MAX_SIZE = 10;
public void produce(Object obj) throws InterruptedException {
synchronized (queue) {
while (queue.size() == MAX_SIZE) {
System.out.println("隊列已滿,生產者等待...");
queue.wait();//隊列已滿,等待消費者消費
}
queue.add(obj);//生產一個元素
System.out.println("生產者生產了一個元素,隊列中元素個數:" + queue.size());
queue.notifyAll();//喚醒所有消費者線程
}
}
public void consume() throws InterruptedException {
synchronized (queue) {
while (queue.isEmpty()) {
System.out.println("隊列為空,消費者等待...");
queue.wait(); //隊列為空,等待生產者生產
}
Object obj = queue.poll();//消費一個元素
System.out.println("消費者消費了一個元素,隊列中元素個數:" + queue.size());
queue.notifyAll();//喚醒所有生產者線程
}
}
}
2. 等待-通知機制的使用
在多線程中,基於等待-通知機制來進行協作,是實現同步的重要方式之一。下面是一個使用等待-通知機制來協作的實例:
public class WaitNotifyDemo {
private static volatile boolean flag = false;
private static final Object obj = new Object();
public static void main(String[] args) {
Thread waitThread = new Thread(new WaitTask(), "WaitThread");
waitThread.start();
SleepUtils.second(1);
Thread notifyThread = new Thread(new NotifyTask(), "NotifyThread");
notifyThread.start();
}
static class WaitTask implements Runnable {
public void run() {
synchronized (obj) {
while (!flag) {
System.out.println(Thread.currentThread() + " flag is false. wait...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + " flag is true. running...");
}
}
}
static class NotifyTask implements Runnable {
public void run() {
synchronized (obj) {
System.out.println(Thread.currentThread() + " hold lock. notify...");
obj.notifyAll();
flag = true;//將flag設置為true
SleepUtils.second(5);
}
synchronized (obj) {
System.out.println(Thread.currentThread() + " hold lock again. sleep...");
SleepUtils.second(5);
}
}
}
}
四、總結
wait和notify是Java中多線程同步的重要工具,在進行線程調度和任務協作時非常重要。使用wait和notify需要注意以下幾點:
- wait和notify方法必須在同步塊中調用。
- 在調用wait方法的時候,需要首先獲取對象鎖,否則會拋出IllegalMonitorStateException異常。
- 在調用wait方法時,線程會自動釋放鎖,進入等待狀態,等待其他線程的通知。
- 在調用notify方法時,也需要首先獲取對象鎖,否則會拋出IllegalMonitorStateException異常。
- 在調用notify方法後,會喚醒一個處於等待狀態的線程,並使其進入就緒狀態。
- wait方法還可以設置等待的最大時間,如果在此時間內沒有被喚醒,則線程會自動蘇醒。
原創文章,作者:OODK,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/148231.html