Java多种方式实现生产者消费者模式

所属分类: 软件编程 / java 阅读数: 125
收藏 0 赞 0 分享

实现需求:两个线程交替打印1,0,打印10轮

java多线程口诀:

  • 高内聚,低耦合
  • 线程操作资源类
  • 判断干活通知
  • 防止虚假唤醒

方式一:使用synchronized和Object的wait和notifyAll方法

wait:使当前线程阻塞

notify,notifyAll唤醒当前线程

/**
 * 两个线程交替打印1,0 打印10轮
 *
 * @author Administrator
 * @version 1.0 2020年7月12日
 * @see ProdConsumerDemo1
 * @since 1.0
 *
 */
class ShareData1 {
 
  public int number = 0;
 
  public synchronized void increment() throws Exception {
    while (number != 0) {
      this.wait();
    }
    number++;
    System.out.println(Thread.currentThread().getName() + " " + number);
    this.notifyAll();
  }
 
  public synchronized void decrement() throws InterruptedException {
    while (number != 1) {
      this.wait();
    }
    number--;
    System.out.println(Thread.currentThread().getName() + " " + number);
    this.notifyAll();
  }
}
 
public class ProdConsumerDemo1 {
 
  public static void main(String[] args) {
    ShareData1 shareData = new ShareData1();
    new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        try {
          shareData.increment();
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }, "A").start();
    new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        try {
          shareData.decrement();
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }, "B").start();
  }
}

输出结果

A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0

方式二:使用jdk1.8的Lock和Condition

class ShareData2 {
 
  private int number = 0;
 
  private Lock lock = new ReentrantLock();
 
  private Condition condition = lock.newCondition();
 
  public void increment() throws Exception {
    lock.lock();
    try {
      while (number != 0) {
        condition.await();
      }
      number++;
      System.out.println(Thread.currentThread().getName() + " " + number);
      condition.signalAll();
    } finally {
      lock.unlock();
    }
  }
 
  public void decrement() throws InterruptedException {
    lock.lock();
    try {
      while (number != 1) {
        condition.await();
      }
      number--;
      System.out.println(Thread.currentThread().getName() + " " + number);
      condition.signalAll();
    } finally {
      // TODO: handle finally clause
      lock.unlock();
    }
  }
}
 
public class ProdConsumerDemo2 {
 
  public static void main(String[] args) {
    ShareData2 shareData = new ShareData2();
    new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        try {
          shareData.increment();
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }, "A").start();
    new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        try {
          shareData.decrement();
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }, "B").start();
  }
}

输出结果

A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0
A 1
B 0

主要是熟悉Lock和Condition的使用

Lock和Condition相比于synchronized,能够精确唤醒

需求:三个线程A,B,C顺序打印,A打印5次,B打印10次,C打印15次,10轮

class ShareData3 {
 
  private int number = 1;
 
  private Lock lock = new ReentrantLock();
 
  private Condition c1 = lock.newCondition();
 
  private Condition c2 = lock.newCondition();
 
  private Condition c3 = lock.newCondition();
 
  public void print5() throws Exception {
    lock.lock();
    try {
      while (number != 1) {
        c1.await();
      }
      number = 2;
      for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName() + " " + i);
      }
      c2.signalAll();
    } finally {
      // TODO: handle finally clause
      lock.unlock();
    }
  }
 
  public void print10() throws InterruptedException {
    lock.lock();
    try {
      while (number != 2) {
        c2.await();
      }
      number=3;
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread().getName() + " " + i);
      }
      c3.signalAll();
    } finally {
      // TODO: handle finally clause
      lock.unlock();
    }
  }
 
  public void print15() throws InterruptedException {
    lock.lock();
    try {
      while (number != 3) {
        c3.await();
      }
      number = 1;
      for (int i = 0; i < 15; i++) {
        System.out.println(Thread.currentThread().getName() + " " + i);
      }
      c1.signalAll();
    } finally {
      // TODO: handle finally clause
      lock.unlock();
    }
  }
}
 
public class ProdConsumerDemo3 {
 
  public static void main(String[] args) {
    ShareData3 shareData3 = new ShareData3();
    new Thread(() -> {
      try {
        for (int i = 0; i < 10; i++) {
          shareData3.print5();
        }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }, "A").start();
    new Thread(() -> {
      try {
        for (int i = 0; i < 10; i++) {
          shareData3.print10();
        }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }, "B").start();
    new Thread(() -> {
      try {
        for (int i = 0; i < 10; i++) {
          shareData3.print15();
        }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }, "C").start();
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

Java实现一个简单的文件上传案例示例代码

这篇文章主要介绍了Java实现一个简单的文件上传案例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

详解在spring中使用JdbcTemplate操作数据库的几种方式

这篇文章主要介绍了详解在spring中使用JdbcTemplate操作数据库的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

java中的switch case语句使用详解

这篇文章主要介绍了java中的switch case语句使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

深入理解Java 线程池

这篇文章主要介绍了Java 线程池的相关资料,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

详解mybatis #{}和${}的区别、传参、基本语法

这篇文章主要介绍了mybatis #{}和${}的区别、传参、基本语法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

MyBatis 中 ${}和 #{}的正确使用方法(千万不要乱用)

这篇文章主要介绍了MyBatis 中 ${}和 #{}的正确使用方法,本文给大家提到了MyBatis 中 ${}和 #{}的区别,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

详解Mybatis中的 ${} 和 #{}区别与用法

这篇文章主要介绍了Mybatis中的 ${} 和 #{}区别与用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Maven安装过程图文详解

这篇文章主要介绍了Maven安装过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
收藏 0 赞 0 分享

SpringBoot登录拦截配置详解(实测可用)

这篇文章主要介绍了SpringBoot登录拦截配置详解(实测可用),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

JAVA 内存溢出案例汇总

这篇文章主要介绍了JAVA 内存溢出案例的汇总,文中讲解非常细致,帮助各位工作学习时避免内存溢出,感兴趣的朋友可以了解下
收藏 0 赞 0 分享
查看更多