zoukankan      html  css  js  c++  java
  • 锁和多线程:生产者与消费者3种实现(四)

     

     

    搞明白 线程 多线程系列

    1.wait notifyAll

    首先使用最传统的wait notifyAll synchronized方式,生产食物后唤醒消费者,食物充足时就等待,不生产食物.

    • wait() 让线程等待
    • notifyAll 唤醒等待线程
    package com.lyf.procon;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 21:09
     */
    public class Food01 {
      private static int num = 0; // 食物数量
      
      public synchronized void add() {
        if (num < 1) {// 判断食物是否充足
          num++;// 生产食物
          notifyAll();// 唤醒消费者
        } else {
          try {
            wait();// 生产者等待
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    
      public synchronized void remove() {
        if (num > 0) {// 判断食物是否充足
          num--; // 消费食物
          notifyAll();// 唤醒生产者
        } else {
          try {
            wait();// 消费者等待
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    
    }
    
    class Producer01 extends Thread{
      private Food01 food01;
    
      public Producer01(Food01 proCon1) {
        this.food01 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food01.add();
          System.out.println(Thread.currentThread().getName() + "生产食物...");
        }
      }
    }
    
    class Consumer01 extends Thread{
      private Food01 food01;
    
      public Consumer01(Food01 proCon1) {
        this.food01 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food01.remove();
          System.out.println(Thread.currentThread().getName() + "消费食物...");
        }
      }
    }
    
    class Test01{
      public static void main(String[] args) throws InterruptedException {
        Food01 food01 = new Food01();
        for (int i = 0; i < 3; i++) {
          new Producer01(food01).start();
          new Consumer01(food01).start();
        }
        
        Thread.sleep(10);
        System.exit(0);// 强制终止程序
      }
    }
    

    2.ReentrantLock

    使用ReentrantLock重入锁和Condition条件实现,创建重入锁lock变量.然后,创建生产者的触发条件producer消费者触发条件consumer.调用

    • consumer.signalAll()唤醒消费者
    • consumer.await()让消费者等待
    • producer.signalAll()唤醒生产者
    • producer.await()让生产者等待
    package com.lyf.procon;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 21:09
     */
    public class Food02 {
      private static int num = 0; // 食物数量
      
      private ReentrantLock lock;
      private Condition producer;// 生产者状态
      private Condition consumer;// 消费者状态
    
      public Food02() {
        lock = new ReentrantLock();
        producer = lock.newCondition();
        consumer = lock.newCondition();
      }
    
      public void add() {
        lock.lock();// 获得锁
        try {
          if (num < 1) {
            num++;
            consumer.signalAll();// 通知消费者
          }else{
            producer.await();// 生产者等待
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();// 释放锁
        }
      }
    
      public void remove() {
        lock.lock();// 获得锁
        try {
          if (num > 0) {
            num--;
            producer.signalAll();// 通知生产者
          }else{
            consumer.await();// 消费者等待
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();// 释放锁
        }
      }
    }
    
    class Producer02 extends Thread{
      private Food02 food02;
    
      public Producer02(Food02 proCon1) {
        this.food02 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food02.add();
          System.out.println(Thread.currentThread().getName() + "生产食物...");
        }
      }
    }
    
    class Consumer02 extends Thread{
      private Food02 food02;
    
      public Consumer02(Food02 proCon1) {
        this.food02 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food02.remove();
          System.out.println(Thread.currentThread().getName() + "消费食物...");
        }
      }
    }
    
    class Test02{
      public static void main(String[] args) throws InterruptedException {
        Food02 food02 = new Food02();
        for (int i = 0; i < 3; i++) {
          new Producer02(food02).start();
          new Consumer02(food02).start();
        }
        
        Thread.sleep(10);
        System.exit(0);// 强制终止程序
      }
    }
    

    3.BlockingDeque

    使用阻塞队列BlockingDeque实现,调用

    • put()在队列尾部添加元素
    • take()在队列头部删除元素
    package com.lyf.procon;
    
    import java.util.concurrent.BlockingDeque;
    import java.util.concurrent.LinkedBlockingDeque;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 21:09
     */
    public class Food03 {
      // 创建阻塞队列
      private BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>(10);
    
      public void add() {
        try {
          blockingDeque.put(1);// 在队列尾部添加元素
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      public void remove() {
        try {
          blockingDeque.take();// 在队列头部删除元素
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
    }
    
    class Producer03 extends Thread{
      private Food03 food03;
    
      public Producer03(Food03 proCon1) {
        this.food03 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food03.add();
          System.out.println(Thread.currentThread().getName() + "生产食物...");
        }
      }
    }
    
    class Consumer03 extends Thread{
      private Food03 food03;
    
      public Consumer03(Food03 proCon1) {
        this.food03 = proCon1;
      }
    
      @Override
      public void run() {
        while (true){
          food03.remove();
          System.out.println(Thread.currentThread().getName() + "消费食物...");
        }
      }
    }
    
    class Test03{
      public static void main(String[] args) throws InterruptedException {
        Food03 food03 = new Food03();
        for (int i = 0; i < 3; i++) {
          new Producer03(food03).start();
          new Consumer03(food03).start();
        }
        
        Thread.sleep(10);
        System.exit(0);// 强制终止程序
      }
    }
    

    参考资料

  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/linyufeng/p/9993120.html
Copyright © 2011-2022 走看看