## **什么是多线程通信**
多个线程对同一个资源的读写操作。
简单实现一个多线程生产者/消费者的读写操作
```
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对象类中最合适吧。(我猜的)