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

网络公司网站建设网站制作

网络公司网站建设,网站制作,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.shuangfujiaoyu.com/news/17017.html

相关文章:

  • 昆明有多少做网站的公司百度seo推广
  • 做图剪片文案网站app接单新网
  • 外贸b2c网站如何做推广天津网络广告公司
  • linux做网站的好处品牌seo推广
  • 中文wordpress企业主题seo和网络推广有什么区别
  • 曲阳网站制作公司外贸网站制作
  • cos领域wordpressseo网站优化方案
  • 杭州网站建设多少钱推广类软文案例
  • wordpress python代码聊城seo
  • wordpress 后面密码忘记在线seo工具
  • 电子商务网站经营特色分析的主要内容包括百度竞价查询
  • 门户网站运营是什么seo教程论坛
  • 做淘宝用那些网站发货seo外推
  • 郑州专业做网站的seo自学网
  • 受欢迎自适应网站建设地址舆情网站入口
  • 软装工作室关键词快速排名seo怎么优化
  • wordpress jpressseo流量是什么意思
  • 通辽市做网站公司国内重大新闻10条
  • 正保建设工程教育网站网络推广方法有哪几种
  • 哪个网站做外贸比较好巨量引擎广告投放平台代理
  • 图片怎么制作南昌网优化seo公司
  • 顺德网站建设多少钱网络舆情
  • 用自己的名字做网站域名网络广告发布
  • 网站开发的必要性微平台推广
  • 找人做网站要注意什么淘宝关键词挖掘工具
  • 免费做网页的网站东莞seo优化排名推广
  • 榆林建设银行的网站网页一键生成app软件
  • seo搜索培训seo优化网站排名
  • 个人网站首页搜索引擎营销成功的案例
  • 宁波网站建设鲤斯设计百度竞价专员