当前位置: 首页 > news >正文

娄底建设企业网站医疗网站建设怎么样

娄底建设企业网站,医疗网站建设怎么样,wordpress怎么安装 centos,wordpress 切换域名文章目录 传统解法解法一:传统解法 (synchronized wait/notifyAll) 的流程解说核心机制生产者流程 (produce)消费者流程 (consume)关键点与缺点 多条件解法解法二:多条件解法 (ReentrantLock Condition) 的流程解说核心机制生产者流程 (produce)消费者…

文章目录

  • 传统解法
      • 解法一:传统解法 (`synchronized` + `wait/notifyAll`) 的流程解说
        • 核心机制
        • 生产者流程 (`produce`)
        • 消费者流程 (`consume`)
        • 关键点与缺点
  • 多条件解法
      • 解法二:多条件解法 (`ReentrantLock` + `Condition`) 的流程解说
        • 核心机制
        • 生产者流程 (`produce`)
        • 消费者流程 (`consume`)
        • 关键优势:精确唤醒

传统解法

package JUC_练习题.生产者消费者.传统解法;import java.util.LinkedList;
import java.util.Queue;public class ProducerConsumerSynchronized {// 共享的缓冲区static class Buffer {private final Queue<Integer> queue = new LinkedList<>();private final int capacity;public Buffer(int capacity) {this.capacity = capacity;}// 生产方法public synchronized void produce(int item) throws InterruptedException {// 如果缓冲区满了,生产者等待while (queue.size() == capacity) {System.out.println(Thread.currentThread().getName() + " 缓冲区满了,等待消费...");wait(); // 释放锁并等待}// 生产物品queue.offer(item);System.out.println(Thread.currentThread().getName() + " 生产了: " + item +",当前数量: " + queue.size());// 通知消费者可以消费了notifyAll();}// 消费方法public synchronized int consume() throws InterruptedException {// 如果缓冲区空了,消费者等待while (queue.isEmpty()) {System.out.println(Thread.currentThread().getName() + " 缓冲区空了,等待生产...");wait(); // 释放锁并等待}// 消费物品int item = queue.poll();System.out.println(Thread.currentThread().getName() + " 消费了: " + item +",剩余数量: " + queue.size());// 通知生产者可以生产了notifyAll();return item;}}public static void main(String[] args) {Buffer buffer = new Buffer(5); // 容量为5的缓冲区// 创建2个生产者for (int i = 1; i <= 2; i++) {new Thread(() -> {try {for (int j = 1; j <= 5; j++) {buffer.produce(j);Thread.sleep(100); // 模拟生产时间}} catch (InterruptedException e) {e.printStackTrace();}}, "生产者" + i).start();}// 创建3个消费者for (int i = 1; i <= 3; i++) {new Thread(() -> {try {for (int j = 1; j <= 3; j++) {buffer.consume();Thread.sleep(200); // 模拟消费时间}} catch (InterruptedException e) {e.printStackTrace();}}, "消费者" + i).start();}}
}

好的,我们来分别对这两个经典的生产者-消费者模型的解法进行详细的流程解说。


解法一:传统解法 (synchronized + wait/notifyAll) 的流程解说

这个方案是Java最基础的线程同步与通信方式,它依赖于每个对象都拥有的“监视器锁”。

核心机制
  • Buffer 对象本身。当一个线程进入任何一个 synchronized 方法(produceconsume)时,它就获得了 buffer 对象的锁。
  • 等待队列:每个锁对象(这里是buffer)只有一个等待队列(Wait Set)。所有调用 wait() 的线程,不管是生产者还是消费者,都会进入这同一个队列里等待。
  • 通信:通过 wait() 释放锁并等待,通过 notifyAll() 唤醒等待队列中的所有线程。
生产者流程 (produce)
  1. 一个生产者线程(比如“生产者1”)调用 buffer.produce()
  2. 它尝试获取 buffer 对象的锁。如果锁空闲,它就成功获得锁。此时,其他任何线程(包括其他生产者和所有消费者)都无法进入 produceconsume 方法。
  3. 它进入 while (queue.size() == capacity) 循环检查条件。
    • 如果缓冲区满了
      • 打印“缓冲区满了,等待消费…”。
      • 调用 wait()。此时,该生产者线程会立即释放它持有的 buffer,并进入 buffer 对象的等待队列中休眠。
    • 如果缓冲区未满
      • 跳出 while 循环。
      • queue 中添加一个物品 (queue.offer(item))。
      • 打印生产信息。
      • 调用 notifyAll()。这个动作会唤醒所有正在 buffer 等待队列中休眠的线程(包括可能在等待的其他生产者所有消费者)。
  4. produce 方法执行完毕,线程退出 synchronized 方法,正常释放锁
消费者流程 (consume)
  1. 一个消费者线程(比如“消费者1”)调用 buffer.consume()
  2. 它获取 buffer 对象的锁。
  3. 它进入 while (queue.isEmpty()) 循环检查条件。
    • 如果缓冲区是空的
      • 打印“缓冲区空了,等待生产…”。
      • 调用 wait()释放 buffer并进入等待队列。
    • 如果缓冲区不空
      • 跳出 while 循环。
      • queue 中取出一个物品 (queue.poll())。
      • 打印消费信息。
      • 调用 notifyAll(),唤醒所有在等待的线程。
  4. consume 方法执行完毕,线程退出 synchronized 方法,正常释放锁
关键点与缺点
  • 优点:实现简单,是Java内置的机制。
  • 缺点:效率较低,存在“惊群效应” (Thundering Herd)。当一个生产者调用 notifyAll() 时,它会唤醒所有线程。但此时缓冲区可能只多了一个位置,那么被唤醒的其他生产者线程会发现条件依然不满足(还是满的),于是它们白白醒来一次,检查完条件后又得继续 wait()。这造成了不必要的线程上下文切换和CPU资源浪费。

多条件解法

package JUC_练习题.生产者消费者.可重入锁和多条件;import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class ProducerConsumerReentrantLock {// 共享的缓冲区static class Buffer {private final Queue<Integer> queue = new LinkedList<>();private final int capacity;// ReentrantLock 和两个条件变量private final ReentrantLock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();  // 缓冲区不满的条件private final Condition notEmpty = lock.newCondition(); // 缓冲区不空的条件public Buffer(int capacity) {this.capacity = capacity;}// 生产方法public void produce(int item) throws InterruptedException {lock.lock(); // 获取锁try {// 如果缓冲区满了,在 notFull 条件上等待while (queue.size() == capacity) {System.out.println(Thread.currentThread().getName() +" 缓冲区满了,在notFull条件上等待...");notFull.await(); // 释放锁并等待}// 生产物品queue.offer(item);System.out.println(Thread.currentThread().getName() + " 生产了: " + item +",当前数量: " + queue.size());// 通知在 notEmpty 条件上等待的消费者notEmpty.signal(); // 精确通知消费者} finally {lock.unlock(); // 释放锁}}// 消费方法public int consume() throws InterruptedException {lock.lock(); // 获取锁try {// 如果缓冲区空了,在 notEmpty 条件上等待while (queue.isEmpty()) {System.out.println(Thread.currentThread().getName() +" 缓冲区空了,在notEmpty条件上等待...");notEmpty.await(); // 释放锁并等待}// 消费物品int item = queue.poll();System.out.println(Thread.currentThread().getName() + " 消费了: " + item +",剩余数量: " + queue.size());// 通知在 notFull 条件上等待的生产者notFull.signal(); // 精确通知生产者return item;} finally {lock.unlock(); // 释放锁}}}public static void main(String[] args) {Buffer buffer = new Buffer(5); // 容量为5的缓冲区// 创建2个生产者for (int i = 1; i <= 2; i++) {new Thread(() -> {try {for (int j = 1; j <= 5; j++) {buffer.produce(j);Thread.sleep(100); // 模拟生产时间}} catch (InterruptedException e) {e.printStackTrace();}}, "生产者" + i).start();}// 创建3个消费者for (int i = 1; i <= 3; i++) {new Thread(() -> {try {for (int j = 1; j <= 3; j++) {buffer.consume();Thread.sleep(200); // 模拟消费时间}} catch (InterruptedException e) {e.printStackTrace();}}, "消费者" + i).start();}}
}

解法二:多条件解法 (ReentrantLock + Condition) 的流程解说

这个方案是JUC(java.util.concurrent)包提供的更现代、更灵活的解决方案。

核心机制
  • :一个显式的 ReentrantLock 对象。通过 lock.lock()lock.unlock() 来控制。
  • 等待队列不再是单一的队列。我们从一个 Lock 对象可以创建出多个 Condition 对象,每个 Condition 对象都拥有自己独立的等待队列
    • notFull 条件:管理所有因“缓冲区已满”而等待的生产者线程。
    • notEmpty 条件:管理所有因“缓冲区为空”而等待的消费者线程。
  • 通信await() 相当于 wait()signal() 相当于 notify()。因为我们有两个独立的条件队列,所以可以实现精确唤醒
生产者流程 (produce)
  1. 生产者线程调用 produce()

  2. 它调用 lock.lock() 获取锁。

  3. 进入 try...finally 块(确保锁一定会被释放)。

  4. 检查 while (queue.size() == capacity) 条件。

    • 如果缓冲区满了
      • 打印“在notFull条件上等待…”。
      • 调用 notFull.await()。生产者线程会释放 lock,并进入 notFull 自己的等待队列中休眠。
    • 如果缓冲区未满
      • 生产物品。
      • 打印信息。
      • 关键一步:调用 notEmpty.signal()。它只会唤醒一个正在 notEmpty 条件队列中等待的线程(也就是一个消费者),而绝对不会去打扰任何在 notFull 队列里等待的其他生产者。
  5. finally 块中的 lock.unlock() 被执行,释放锁。

消费者流程 (consume)
  1. 消费者线程调用 consume()

  2. 调用 lock.lock() 获取锁。

  3. 检查 while (queue.isEmpty()) 条件。

    • 如果缓冲区是空的
      • 打印“在notEmpty条件上等待…”。
      • 调用 notEmpty.await()。消费者线程会释放 lock,并进入 notEmpty 自己的等待队列中休眠。
    • 如果缓冲区不空
      • 消费物品。
      • 打印信息。
      • 关键一步:调用 notFull.signal()。它只会唤醒一个正在 notFull 条件队列中等待的线程(也就是一个生产者)。
  4. finally 块中的 lock.unlock() 被执行,释放锁。

关键优势:精确唤醒
  • 效率高ReentrantLock + Condition 的方案通过分离等待队列,实现了精确唤醒。生产者只唤醒消费者,消费者只唤醒生产者。这完全避免了“惊群效应”,使得线程调度非常高效。
  • 逻辑清晰:代码的意图更明确,notFull.await() 就是在等“不满”的条件,notEmpty.signal() 就是在通知“不空”这个消息。
  • 功能更强ReentrantLockCondition 提供了更丰富的功能,如可中断的等待、定时的等待、公平锁等。

总而言之,多条件解法是传统解法的一个全面升级,它通过更精细的控制,解决了传统解法的效率瓶颈。

http://www.yayakq.cn/news/984225/

相关文章:

  • 局域网网站制作我的世界做图片网站
  • 怎么做视频解析网站外链网
  • 深圳低价做网站aspnet网站开发源码
  • 山网站建设绿色长春app
  • 月嫂网站源码如何提升百度关键词排名
  • 太原做网站建设工程教育网校官网
  • 网页设计公司网站wordpress导航位置
  • 民间it网站建设第一设计
  • 中型网站开发语言seo公司后付费
  • h5微网站建设多少钱网站是先制作后上线么
  • 区域信息网站怎么做wordpress头像加载
  • 如何手机做网站网站建设的发展序列
  • 腾讯云网站建设视频教程宁波荣胜网络科技有限公司
  • 以下可以制作二维码的网站为做网站如何备案
  • 网站可以做弹窗广告么户型图在哪个网站找
  • 小型网站建设步骤wordpress怎么做相关相似文章链接
  • 江西那家做网站公司好中江建设局网站
  • 云主机做网站域名打不开高端大气传媒公司名字
  • tp5网站开发模板如何交换优质友情链接
  • 做网站效果图wordpress后台拿shell
  • 不是网站开发语言的是网站建设如何交税
  • 网站排名监控工具国内建网站多少钱
  • 广西建设局网站首页手机移动端网站建设
  • 网站的搜索框如何做珠海专业网站建设价格
  • 网站域名好了下一步建设银行信用卡中心网站
  • 安徽富通建设集团有限公司网站网页编辑图片
  • win8网站设计网站方案制作的培训
  • 响应式制作网站建设东莞网络营销网络培训学校
  • 手机网站建设书籍网站编辑是做什么
  • 永康住房和城乡建设局网站东莞网站快速优化排名