ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## **什么是多线程通信** 多个线程对同一个资源的读写操作。 简单实现一个多线程生产者/消费者的读写操作 ``` 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对象类中最合适吧。(我猜的)