線程通信
什么是線程通信
- 當多個線程共同操作共享的資源時,線程間通過某種方式互相告知自己的的狀態,以相互協調,并避免無效的資源爭奪。
線程通信的常見模型(生產者與消費者模型)
- 生產者線程負責生產數據
- 消費者線程負責消費生產者生產的數據
- 注意:生產者生產完數據應該等待自己,通知消費者消費;消費者消費完數據也應該等待自己,再通知生產者生產
Object類的等待和喚醒方法
方法名稱 | 說明 |
---|---|
void wait() | 讓當前線程等待并釋放所占鎖,直到另一個線程調用notify()方法或者notifyAll()方法 |
void notify() | 喚醒正在等待的單個線程 |
void notifyAll() | 喚醒正在等待的所有線程 |
注意?
- 上述方法應該使用當前同步鎖對象進行調用
案例
需求:3個生產者線程,負責生產包子,每個線程每次只能生產一個包子放在桌子上,2個消費者線程負責吃包子,沒人每次只能從桌子上拿一個包子吃。
ThreadTest類
public class ThreadTest {public static void main(String[] args) {Desk desk = new Desk();// 創建3個生產者線程(3個廚師)new Thread(() -> {while (true) {desk.put();}},"廚師1").start();new Thread(() -> {while (true) {desk.put();}},"廚師2").start();new Thread(() -> {while (true) {desk.put();}},"廚師3").start();// 創建2個消費者線程(2個吃貨)new Thread(() -> {while (true) {desk.get();}},"吃貨1").start();new Thread(() -> {while (true) {desk.get();}},"吃貨2").start();}
}
Desk類
import java.util.ArrayList;
import java.util.List;public class Desk {public List<String> list = new ArrayList<>();// 放一個包子的方法// 廚師1 廚師2 廚師3public synchronized void put(){try {String name = Thread.currentThread().getName();// 判斷是否有包子if (list.size() == 0){list.add(name + "做的肉包子");System.out.println(name + "做了一個肉包子");Thread.sleep(2000);// 喚醒別人,等待自己this.notifyAll();this.wait();}else {// 有包子,不做了// 喚醒別人,等待自己this.notifyAll();this.wait();}} catch (Exception e) {e.printStackTrace();}}// 吃貨1 吃貨2public synchronized void get() {try {String name = Thread.currentThread().getName();// 判斷是否有包子if (list.size() == 1){// 有包子,吃了System.out.println(name + "吃了:" + list.get(0));list.clear();Thread.sleep(1000);this.notifyAll();this.wait();}else {// 沒有包子this.notifyAll();this.wait();}} catch (InterruptedException e) {e.printStackTrace();}}
}