## **什么是多線程通信**
多個線程對同一個資源的讀寫操作。
簡單實現一個多線程生產者/消費者的讀寫操作
```
class Person {
public String name;
public String gender;
}
// 生產者
class Produce extends Thread {
private Person person;
public Produce(Person person) {
this.person = person;
}
@Override
public void run() {
int count = 0;
while (true) {
if (count == 0) {
person.name = "小王";
person.gender = "男";
} else {
person.name = "小林";
person.gender = "女";
}
count = (count + 1) % 2;
}
}
}
// 消費者
class Consumer extends Thread {
private Person person;
public Consumer(Person person) {
this.person = person;
}
@Override
public void run() {
while (true) {
System.out.println(person.name + ":" + person.gender);
}
}
}
class test {
public static void main(String[] args) {
Person person = new Person();
Produce produce = new Produce(person);
Consumer consumer = new Consumer(person);
produce.start();
consumer.start();
}
}
運行結果片段
小林:女
小林:女
小王:男
小王:女
小王:男
```
很明顯小王性別及其不穩定,造成線程安全問題。第一時間想到的肯定是加入synchronized鎖解決多線程原子性問題
Produce方法中加入synchronized
```
class Produce extends Thread {
...
@Override
public void run() {
int count = 0;
while (true) {
synchronized (person) {
if (count == 0) {
person.name = "小王";
person.gender = "男";
} else {
person.name = "小林";
person.gender = "女";
}
count = (count + 1) % 2;
}
}
}
}
```
Consumer方法中加入synchronized
```
class Consumer extends Thread {
...
@Override
public void run() {
while (true) {
synchronized (person) {
System.out.println(person.name + ":" + person.gender);
}
}
}
}
```
運行結果
```
小林:女
小林:女
小林:女
小林:女
小林:女
小林:女
小王:男
小王:男
小王:男
小王:男
小王:男
小王:男
```
加入synchronized 后小王和小林的性別也都正常了,但是并不是我們想要的理想輸出結果。我們想要的是寫一個讀一個的操作,那么就繼續改造代碼加入Object對象類中提供的wait、notify方法。
1. 共享對象中加入線程標識flag字段
```
class Person {
public String name;
public String gender;
public boolean flag = false;
}
```
1. Produce方法中加入wait、notify方法
```
class Produce extends Thread {
...
@Override
public void run() {
int count = 0;
while (true) {
synchronized (person) {
if (person.flag) {
try {
person.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
...
person.flag = true;
person.notify();
}
}
}
}
```
1. Consumer方法中加入wait、notify方法
```
class Consumer extends Thread {
...
@Override
public void run() {
while (true) {
synchronized (person) {
if (!person.flag) {
try {
person.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(person.name + ":" + person.gender);
person.flag = false;
person.notify();
}
}
}
}
```
運行結果
```
小林:女
小王:男
小林:女
小王:男
小林:女
小王:男
```
這不就是我們想要的結果嘛,好吧那我們就聊聊wait、notify吧
## **wait、notify方法**
1. wait
該方法用來將當前線程置入休眠狀態,直到在其他線程調用此對象的notify()方法或notifyAll()方法將其喚醒
在調用wait()之前,線程必須要獲得該對象的對象級別鎖,因此只能在同步方法或同步塊中調用wait()方法。進入wait()方法后,當前線程釋放鎖。
2. notify
該方法喚醒在此對象監視器上等待的單個線程。如果有多個線程都在此對象上等待,則會隨機選擇喚醒其中一個線程,對其發出通知notify(),并使它等待獲取該對象的對象鎖
總結兩個方法:wait()使線程停止運行,notify()使停止運行的線程繼續運行。
因為涉及到對象鎖,他們必須都放在synchronized中來使用,并且synchronized鎖對象必須一致。
**為啥wait、notify封裝在Object對象類中呢?**
wait、notify必須在synchronized中使用、synchronized鎖的對象可以是任意的對象、Object類又是所以類的祖先、那么似乎封裝在Object對象類中最合適吧。(我猜的)