此篇博客以 生产面包🍞/消费面包🍞例子为例,所以首先看一个synchronized(同步锁机制)(生产者 消费者)&等待唤醒机制的案例
synchronized(同步锁机制)(生产者 消费者)&等待唤醒机制的案例:
package android.java.thread20; /** * 描述资源 */ class Res { /** * name 是共享数据,被Thread-0 Thread-1公用使用 */ private String name; /** * id 是共享数据,被Thread-0 Thread-1公用使用 */ private int id; /** * flag 是共享数据,被Thread-0 Thread-1公用使用 */ private boolean flag; // 定义标记 默认第一次为false /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void put(String name) { /** * 生产之前判断标记 */ if (!flag) { // 开始生产 id += 1; this.name = name + " 商品编号:" + id; System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name); // 生产完毕 /** * 修改标记 */ flag = true; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void out() { /** * 消费之前判断标记 */ if (flag) { // 开始消费 System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name); // 消费完毕 /** * 修改标记 */ flag = false; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 描述生产者任务 */ class ProduceRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ProduceRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.put("面包🍞"); } } } /** * 描述消费者任务 */ class ConsumeRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ConsumeRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.out(); } } } /** * 多线程通讯案例 */ public class ThreadCommunicationDemo { public static void main(String[] args) { // 创建资源对象 Res res = new Res(); // 创建生产者任务 ProduceRunnable produceRunnable = new ProduceRunnable(res); // 创建消费者任务 ConsumeRunnable consumeRunnable = new ConsumeRunnable(res); // 启动生产者任务 new Thread(produceRunnable).start(); // 启动消费者任务 new Thread(consumeRunnable).start(); } }
执行结果:
执行结果,和谐了 生产一个 消费一个:

以上的案例:synchronized(同步锁机制)(生产者 消费者)&等待唤醒机制的案例,是使用synchronized(同步锁🔒机制)中操作{ 锁.wait(); 锁.notify(). 锁.notifyAll(); }
wait(); 等待/冻结 :可以将线程冻结,释放CPU执行资格,释放CPU执行权,并把此线程临时存储到线程池
notify(); 唤醒线程池里面 任意一个线程,没有顺序;
notifyAll(); 唤醒线程池里面,全部的线程;
注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着,而同步锁🔒,就是synchronized(锁)
以下的案例:可以理解是 synchronized(同步锁机制)(生产者 消费者)&等待唤醒机制 的升级版,使用Lock接口来实现:同步锁机制/等待/唤醒
把synchronized等待唤醒机制的案例 修改成>>> Lock等待唤醒机制的案例:
使用规则:必须使用 try {}finally{} 意思是:万一发生异常 或者 发生什么 ....... 导致没有释放锁🔒,从而引发严重错误❌, 加入以下代码控制的意思是:不管发生什么一定会释放锁🔒
try { }finally { // 释放锁🔒 }
Condition监视器:可以操作等待唤醒机制
// 定义一个锁🔒 private Lock lock = new ReentrantLock(); // 定义监视器 监视器可以操作等待唤醒机制 private Condition condition = lock.newCondition(); // 🔒锁定 锁住 lock.lock(); // 多线程/多地方调用 执行操作共享数据的代码 ....... // 唤醒 condition.signal(); // 等待 condition.await(); // 🔓释放锁 lock.unlock();
使用Lock接口来实现:同步锁机制/等待/唤醒的案例:
package android.java.thread20; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 描述资源 */ class Res { /** * name 是共享数据,被Thread-0 Thread-1公用使用 */ private String name; /** * id 是共享数据,被Thread-0 Thread-1公用使用 */ private int id; /** * flag 是共享数据,被Thread-0 Thread-1公用使用 */ private boolean flag; // 定义标记 默认第一次为false /** * Lock是接口不是直接实例化,需要实例化Lock的实现类ReentrantLock,这样就创建了一把锁🔒 */ private Lock lock = new ReentrantLock(); /** * 定义监视器对象 注意:⚠ Lock可以绑定多个监视器,而synchronized只能绑定一个监视器,监视器可以等待/唤醒机制 */ private Condition condition = lock.newCondition(); public void put(String name) { try { /** * 锁🔒定 操作共享数据的代码 * 只要锁定后 不管CPU如何疯狂的切换执行,只要同步代码块里面的代码没有执行完, * 就不准其他线程进来执行,这样就保证了多线程操作共享数据的安全新 */ lock.lock(); /** * 生产之前判断标记 */ if (!flag) { // 开始生产 id += 1; this.name = name + " 商品编号:" + id; System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name); // 生产完毕 /** * 修改标记 */ flag = true; /** * 唤醒 冻结的线程,如果没有就是空唤醒,Java是支持的 * notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着,现在没有了synchronized就等于没有了锁,所以不能使用了,否则会报错 * condition.signal(); 的锁🔒是 定义的lock,没有lock就没有condition.signal();,这才是面向对象思想的体现 */ condition.signal(); /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { /** * wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着,现在没有了synchronized就等于没有了锁,所以不能使用了,否则会报错 * condition.await(); 的锁🔒是 定义的lock,没有lock就没有condition.await();,这才是面向对象思想的体现 */ condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } finally { /** * 释放锁🔓,锁是资源 * 释放锁🔒后 就不再持有锁🔒 * 当不再持有锁🔒,其他然后线程都可以执行进入代码了 * * 注意⚠:一旦锁定后,就一旦要释放锁,否则所以线程都进不了锁定的代码 */ lock.unlock(); // System.out.println("释放锁🔒"); } } public void out() { try { /** * 锁🔒定 操作共享数据的代码 * 只要锁定后 不管CPU如何疯狂的切换执行,只要同步代码块里面的代码没有执行完, * 就不准其他线程进来执行,这样就保证了多线程操作共享数据的安全新 */ lock.lock(); /** * 消费之前判断标记 */ if (flag) { // 开始消费 System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name); // 消费完毕 /** * 修改标记 */ flag = false; /** * 唤醒 冻结的线程,如果没有就是空唤醒,Java是支持的 * notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着,现在没有了synchronized就等于没有了锁,所以不能使用了,否则会报错 * condition.signal(); 的锁🔒是 定义的lock,没有lock就没有condition.signal();,这才是面向对象思想的体现 */ condition.signal(); /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { /** * wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着,现在没有了synchronized就等于没有了锁,所以不能使用了,否则会报错 * condition.await(); 的锁🔒是 定义的lock,没有lock就没有condition.await();,这才是面向对象思想的体现 */ condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } finally { /** * 释放锁🔓,锁是资源 * 释放锁🔒后 就不再持有锁🔒 * 当不再持有锁🔒,其他然后线程都可以执行进入代码了 * * 注意⚠:一旦锁定后,就一旦要释放锁,否则所以线程都进不了锁定的代码 */ lock.unlock(); // System.out.println("释放锁🔒"); } } } /** * 描述生产者任务 */ class ProduceRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ProduceRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.put("面包🍞"); } } } /** * 描述消费者任务 */ class ConsumeRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ConsumeRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.out(); } } } /** * 多线程通讯案例 */ public class ThreadCommunicationDemo { public static void main(String[] args) { // 创建资源对象 Res res = new Res(); // 创建生产者任务 ProduceRunnable produceRunnable = new ProduceRunnable(res); // 创建消费者任务 ConsumeRunnable consumeRunnable = new ConsumeRunnable(res); // 启动生产者任务 new Thread(produceRunnable).start(); // 启动消费者任务 new Thread(consumeRunnable).start(); } }
执行结果,和synchronized案例一,一样的效果:

浙公网安备 33010602011771号