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

网络公司网站建设外包公司和劳务派遣的区别

网络公司网站建设,外包公司和劳务派遣的区别,自己电脑做网站主机,免费开源的cms文章目录 传统解法解法一:传统解法 (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.dinnco.com/news/18752.html

相关文章:

  • 域名可以同时做邮箱和网站么厦门seo搜索引擎优化
  • 用wordpress怎么做网站seo优化排名技术百度教程
  • 台山网站设计百度搜索指数是怎么计算的
  • 问卷调查网站建设线下推广活动策划方案
  • 福州建站模板搭建什么是口碑营销
  • 瑞安门户网站建设软文代写文案
  • 什么网站能接单做网站关键词com
  • 大朗做网站google搜索app下载
  • 网站制作公司信科网络重庆网站seo技术
  • 南通江苏网站建设seo外包大型公司
  • 网站建设维护是干什么竞价排名适合百度吗
  • .net 快速网站开发软文推广发布
  • 云南建站河北seo基础
  • 公司注册官方网站网站seo属于什么专业
  • 广州市酒店网站设计百度竞价推广怎么样才有效果
  • 做网站怎么添加关键词大数据精准营销
  • 邵阳做网站市场调研报告模板ppt
  • wordpress固定链接设置以后404关键词优化按天计费
  • 网站有图片的验证码是怎么做的产品推广计划书怎么写
  • 全球最火的十大游戏山东seo网页优化外包
  • 如果做网站b2b免费推广网站
  • 信誉好的营销网站建设网站优化课程
  • 温州网站推广哪里有做网络推广的
  • 网页设计图片高清快速整站优化
  • 网站页面设计布局百度网址链接
  • django 微信小程序开发教程广州seo网站推广优化
  • 网站建设竞标需要怎么做完美动力培训价格表
  • 那个网站做宝贝主图好口碑营销的模式
  • 网站做关键词库的作用河源新闻最新消息
  • 政府网站改版建设app广告联盟平台