4、關于 Object 類中的 wait 和 notify 方法。(生產者和消費者模式!)
第一:wait 和 notify 方法不是線程對象的方法,是 java 中任何一個 java 對象都有的方法,因為這兩個方法是 Object 類中自帶的。
wait 方法和 notify 方法不是通過線程對象調用的。
第二:wait() 方法作用?
Object o = new Object();
o.wait();
表示:讓正在 o 對象上活動的線程進入等待狀態,無期限等待,直到被喚醒為止。
o.wait(); 方法的調用,會讓“當前線程(正在 o 對象上活動的線程)”進入等待狀態。
第三:notify方法作用?
Object o = new Object();
o.notify();
表示:喚醒正在 o 對象上等待的線程。
notifyAll() 方法:
這個方法是喚醒 o 對象上處于等待的所有線程。
例:
package com.su.test.threadtest;
import java.util.ArrayList;
import java.util.List;
/**
- @author : sumeiping
- @date : 2022-02-01 16:41
- 1、使用 wait 方法和 notify 方法實現“生產者和消費者模式”
- 2、什么是“生產者和消費者模式”
-
生產線程負責生產,消費線程負責消費。
-
生產線程和消費線程要達到均衡。
-
這是一種特殊的業務需求,在這種特殊的情況下要使用 wait 方法和 notify 方法。
- 3、wait 和 notify 方法不是線程對象的方法,是普通 java 對象都有的方法。java.lang.Object 根類
- 4、wait 方法和 notify 方法建立在線程同步的基礎之上。因為多線程要同時操作一個倉庫。有線程安全問題。
- 5、wait 方法作用:o.wait() 讓正在 o 對象上活動的線程 t 進入等待狀態,并且釋放掉 t 線程之前占有的 o 對象的鎖。
- 6、notify 方法作用:o.notify() 讓正在 o 對象上等待的線程喚醒,只是通知,不會釋放 o 對象上之前占有的鎖。
- 7、模擬這樣一個需求:
-
倉庫我們采用 List 集合。
-
List 集合中假設只能存儲 1 個元素。
-
1 個元素就表示倉庫滿了。
-
如果 List 集合中元素個數是 0,就表示倉庫空了。
-
保證 List 集合中永遠都是最多存儲 1 個元素。
-
必須做到這種效果:生產 1 個消費 1 個。
*/
public class WaitNotify {
public static void main(String[] args) {
// 創建一個倉庫對象,共享的。
List list = new ArrayList();
// 創建2個線程對象// 生產者線程對象Thread t1 = new Thread(new Producer(list));t1.setName("生產者線程");// 消費者線程對象Thread t2 = new Thread(new Consumer(list));t2.setName("消費者線程");// 啟動線程t1.start();t2.start();/*** 生產者線程--->java.lang.Object@47a2a66c* 消費者線程--->java.lang.Object@47a2a66c* 倉庫已經空了* 生產者線程--->java.lang.Object@496550e8* 消費者線程--->java.lang.Object@496550e8* 倉庫已經空了* 生產者線程--->java.lang.Object@4d5acd1c* 倉庫已經有1個元素了* 消費者線程--->java.lang.Object@4d5acd1c* 倉庫已經空了* 生產者線程--->java.lang.Object@8585ad3* 倉庫已經有1個元素了* 消費者線程--->java.lang.Object@8585ad3* 生產者線程--->java.lang.Object@5a9b1c72* 消費者線程--->java.lang.Object@5a9b1c72* 生產者線程--->java.lang.Object@399af5d9* 倉庫已經有1個元素了* 消費者線程--->java.lang.Object@399af5d9* 生產者線程--->java.lang.Object@22b3eddb* 倉庫已經有1個元素了* 消費者線程--->java.lang.Object@22b3eddb* 倉庫已經空了* 生產者線程--->java.lang.Object@6877a59c* ..........*/
}
}
// 生產線程
class Producer implements Runnable{
// 倉庫
private List list;
public Producer(){}
public Producer(List list) {this.list = list;
}@Override
public void run() {// 一直生產(使用死循環來模擬一直生產)while (true){// 給倉庫對象list加鎖synchronized (list){if (list.size() > 0){ // 大于 0,說明倉庫中已經有 1 個元素了。System.out.println("倉庫已經有1個元素了");try {list.wait(); // 當線程進入等待狀態,并且釋放 Producer 之前占有的 list 集合的鎖。} catch (InterruptedException e) {e.printStackTrace();}}// 程序執行到這來說明倉庫是空的,可以生產Object obj = new Object();list.add(obj);System.out.println(Thread.currentThread().getName() + "--->" + obj);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 喚醒消費者進行消費//list.notify();list.notifyAll();}}
}
}
// 消費線程
class Consumer implements Runnable{
private List list;
public Consumer(){}
public Consumer(List list){this.list = list;
}@Override
public void run() {// 一直消費while (true){synchronized (list){if (list.size() == 0){System.out.println("倉庫已經空了");try {list.wait(); // 倉庫已經空了。消費者線程等待,釋放掉 list 集合的鎖} catch (InterruptedException e) {e.printStackTrace();}}// 程序執行到這里說明倉庫中有數據,可以消費Object obj = list.remove(0);System.out.println(Thread.currentThread().getName() + "--->" + obj);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 喚醒生產者進行生產//list.notify();list.notifyAll();}}
}
}