JUC并发编程学习笔记(三)生产者和消费者问题

吴旭华  金牌会员 | 2023-12-1 07:50:56 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 909|帖子 909|积分 2727

生产者和消费者问题

synchronized版-> wait/notify
juc版->Lock
面试:单例模式、排序算法、生产者和消费者、死锁
生产者和消费者问题 Synchronized版
  1. package org.example.pc;
  2. public class A {
  3.     public static void main(String[] args) {
  4.         Date date = new Date();
  5.         new Thread(()->{
  6.             for (int i = 0; i < 20; i++) {
  7.                 date.increment();
  8.             }
  9.         },"A").start();
  10.         new Thread(()->{
  11.             for (int i = 0; i < 20; i++) {
  12.                 date.decrement();
  13.             }
  14.         },"B").start();
  15.     }
  16. }
  17. //判断等待、业务、通知
  18. class Date{
  19.     private int number = 0;
  20.     public synchronized void increment(){
  21.         if (number!=0){
  22.             try {
  23.                 //不等于0就让该线程等待
  24.                 this.wait();
  25.             } catch (InterruptedException e) {
  26.                 throw new RuntimeException(e);
  27.             }
  28.         }
  29.         number++;
  30. //        打印加完后的值
  31.         System.out.println(Thread.currentThread().getName()+"=>"+number);
  32. //        通知其他线程,我完成了
  33.         this.notify();
  34.     }
  35.     public synchronized void decrement(){
  36.         if (number!=1){
  37.             try {
  38.                 this.wait();
  39.             } catch (InterruptedException e) {
  40.                 throw new RuntimeException(e);
  41.             }
  42.         }
  43.         number--;
  44.         System.out.println(Thread.currentThread().getName()+"=>"+number);
  45.         this.notify();
  46.     }
  47. }
复制代码
存在的问题:A、B、C、D四个线程
在线程中判断业务完成唤醒等待应该使用while循环判断,而非if判断,因为if判断值判断一次,在线程中存在一种状态叫虚假唤醒。
JUC版生产者和消费者问题
代码实现
  1. package org.example.pc;
  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. //判断等待、业务、通知
  6. public class Date {
  7.     private int number = 0;
  8.     private Lock lock = new ReentrantLock();
  9.     private Condition inCondition = lock.newCondition();
  10.     public void increment() {
  11.         try {
  12.             lock.lock();
  13.             while (number != 0) {
  14.                 inCondition.await();
  15.             }
  16.             number++;
  17. //        打印加完后的值
  18.             System.out.println(Thread.currentThread().getName() + "=>" + number);
  19. //        通知其他线程,我完成了
  20.             inCondition.signalAll();
  21.         } catch (Exception e) {
  22.             e.printStackTrace();
  23.         } finally {
  24.             lock.unlock();
  25.         }
  26.     }
  27.     public void decrement() {
  28.         try {
  29.             lock.lock();
  30.             while (number != 1) {
  31.                 inCondition.await();
  32.             }
  33.             number--;
  34.             System.out.println(Thread.currentThread().getName() + "=>" + number);
  35.             inCondition.signalAll();
  36.         } catch (Exception e) {
  37.             e.printStackTrace();
  38.         } finally {
  39.             lock.unlock();
  40.         }
  41.     }
  42. }
复制代码
Condition 精准的通知唤醒线程
在传统并发编程中,通过notifily唤醒线程后所有线程都是随机获取到资源的,JUC中可以通过Condition来精准的控制要唤醒哪一个线程资源。任何一个新技术的出现都不会只是为了实现之前已有的效果
代码实现
  1. package org.example.pc;
  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. public class C {
  6.     public static void main(String[] args) {
  7.         DateC dateC = new DateC();
  8.         new Thread(()->{
  9.             for (int i = 0; i < 10; i++) dateC.plantA();
  10.         },"A").start();
  11.         new Thread(()->{
  12.             for (int i = 0; i < 10; i++) dateC.plantB();
  13.         },"B").start();
  14.         new Thread(()->{
  15.             for (int i = 0; i < 10; i++) dateC.plantC();
  16.         },"C").start();
  17.     }
  18. }
  19. class DateC {
  20.     private int number = 1;
  21.     private Lock lock = new ReentrantLock();
  22.     private Condition inCondition1 = lock.newCondition();
  23.     private Condition inCondition2 = lock.newCondition();
  24.     private Condition inCondition3 = lock.newCondition();
  25.    public void plantA(){
  26.        try {
  27.            lock.lock();
  28.            while (number!=1){
  29.                inCondition1.await();
  30.            }
  31.            System.out.println(Thread.currentThread().getName());
  32.            number=2;
  33.            inCondition2.signal();
  34.        }catch (Exception e){
  35.            e.printStackTrace();
  36.        }finally {
  37.            lock.unlock();
  38.        }
  39.    }
  40.     public void plantB(){
  41.         try {
  42.             lock.lock();
  43.             while (number!=2){
  44.                 inCondition2.await();
  45.             }
  46.             System.out.println(Thread.currentThread().getName());
  47.             number=3;
  48.             inCondition3.signal();
  49.         }catch (Exception e){
  50.             e.printStackTrace();
  51.         }finally {
  52.             lock.unlock();
  53.         }
  54.     }
  55.     public void plantC(){
  56.         try {
  57.             lock.lock();
  58.             while (number!=3){
  59.                 inCondition3.await();
  60.             }
  61.             System.out.println(Thread.currentThread().getName());
  62.             number=1;
  63.             inCondition1.signal();
  64.         }catch (Exception e){
  65.             e.printStackTrace();
  66.         }finally {
  67.             lock.unlock();
  68.         }
  69.     }
  70. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

吴旭华

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表