Java生产者消费者是最基础的线程同步问题,java岗面试中还是很容易遇到的,之前没写过多线程的代码,面试中被问到很尬啊,面完回来恶补下。在网上查到大概有5种生产者消费者的写法,分别如下。

  1. 用synchronized对存储加锁,然后用object原生的wait() 和 notify()做同步。
  2. 用concurrent.locks.Lock,然后用condition的await() 和signal()做同步。
  3. 直接使用concurrent.BlockingQueue。
  4. 使用PipedInputStream/PipedOutputStream。
  5. 使用信号量semaphore。  

我的理解,生产者消费者模式,其实只要保证在存储端同一时刻只有一个线程读或写就不会有问题,然后再去考虑线程同步。方法1 2 5都比较类似,都是加锁来限制同一时刻只能有一个读或写。而方法3 4其实是在存储内部去保证读和写的唯一的,最低层肯定还是通过锁机制来实现的,java底层代码都封装好了而已。  

我自己尝试写了下前三种,代码如下: 

synchronized版本

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. public class ProducerAndConsumer {
  4. private final int MAX_LEN = 10;
  5. private Queue<Integer> queue = new LinkedList<Integer>();
  6. class Producer extends Thread {
  7. @Override
  8. public void run() {
  9. producer();
  10. }
  11. private void producer() {
  12. while(true) {
  13. synchronized (queue) {
  14. while (queue.size() == MAX_LEN) {
  15. queue.notify();
  16. System.out.println("当前队列满");
  17. try {
  18. queue.wait();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. queue.add(1);
  24. queue.notify();
  25. System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
  26. try {
  27. Thread.sleep(500);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }
  34. }
  35. class Consumer extends Thread {
  36. @Override
  37. public void run() {
  38. consumer();
  39. }
  40. private void consumer() {
  41. while (true) {
  42. synchronized (queue) {
  43. while (queue.size() == 0) {
  44. queue.notify();
  45. System.out.println("当前队列为空");
  46. try {
  47. queue.wait();
  48. } catch (InterruptedException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. queue.poll();
  53. queue.notify();
  54. System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
  55. try {
  56. Thread.sleep(500);
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. }
  62. }
  63. }
  64. public static void main(String[] args) {
  65. ProducerAndConsumer pc = new ProducerAndConsumer();
  66. Producer producer = pc.new Producer();
  67. Consumer consumer = pc.new Consumer();
  68. producer.start();
  69. consumer.start();
  70. }
  71. }

lock版实现,使用了condition做线程之间的同步。

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. /**
  7. * version 1 doesn't use synchronized to improve performance
  8. */
  9. public class ProducerAndConsumer1 {
  10. private final int MAX_LEN = 10;
  11. private Queue<Integer> queue = new LinkedList<Integer>();
  12. private final Lock lock = new ReentrantLock();
  13. private final Condition condition = lock.newCondition();
  14. class Producer extends Thread {
  15. @Override
  16. public void run() {
  17. producer();
  18. }
  19. private void producer() {
  20. while(true) {
  21. lock.lock();
  22. try {
  23. while (queue.size() == MAX_LEN) {
  24. System.out.println("当前队列满");
  25. try {
  26. condition.await();
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. queue.add(1);
  32. condition.signal();
  33. System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
  34. try {
  35. Thread.sleep(500);
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. } finally {
  40. lock.unlock();
  41. }
  42. }
  43. }
  44. }
  45. class Consumer extends Thread {
  46. @Override
  47. public void run() {
  48. consumer();
  49. }
  50. private void consumer() {
  51. while (true) {
  52. lock.lock();
  53. try {
  54. while (queue.size() == 0) {
  55. System.out.println("当前队列为空");
  56. try {
  57. condition.await();
  58. } catch (InterruptedException e) {
  59. e.printStackTrace();
  60. }
  61. }
  62. queue.poll();
  63. condition.signal();
  64. System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
  65. try {
  66. Thread.sleep(500);
  67. } catch (InterruptedException e) {
  68. e.printStackTrace();
  69. }
  70. } finally {
  71. lock.unlock();
  72. }
  73. }
  74. }
  75. }
  76. public static void main(String[] args) {
  77. ProducerAndConsumer pc = new ProducerAndConsumer();
  78. Producer producer = pc.new Producer();
  79. Consumer consumer = pc.new Consumer();
  80. producer.start();
  81. consumer.start();
  82. }
  83. }

BlockingQueue版实现

  1. import java.util.Random;
  2. import java.util.concurrent.BlockingQueue;
  3. import java.util.concurrent.LinkedBlockingQueue;
  4. public class ProducerAndConsumer {
  5. private BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(10);
  6. class Producer extends Thread {
  7. @Override
  8. public void run() {
  9. producer();
  10. }
  11. private void producer() {
  12. while(true) {
  13. try {
  14. queue.put(1);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
  19. try {
  20. Thread.sleep(new Random().nextInt(1000)+500);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }
  26. }
  27. class Consumer extends Thread {
  28. @Override
  29. public void run() {
  30. consumer();
  31. }
  32. private void consumer() {
  33. while (true) {
  34. try {
  35. queue.take();
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
  40. try {
  41. Thread.sleep(new Random().nextInt(1000)+500);
  42. } catch (InterruptedException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }
  48. public static void main(String[] args) {
  49. ProducerAndConsumer pc = new ProducerAndConsumer();
  50. Producer producer = pc.new Producer();
  51. Consumer consumer = pc.new Consumer();
  52. producer.start();
  53. consumer.start();
  54. }
  55. }

版权声明:本文为博主原创文章,转载请注明出处。 博客地址:https://xindoo.blog.csdn.net/

Java生产者消费者的三种实现的更多相关文章

  1. java实现生产者/消费者的三种方式

    package com.wenki.thread; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQue ...

  2. 基于Java 生产者消费者模式(详细分析)

    Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...

  3. java解析xml的三种方法

    java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...

  4. java中 this 的三种用法

    Java中this的三种用法 调用属性 (1)this可以调用本类中的任何成员变量 调用方法(可省略) (2)this调用本类中的成员方法(在main方法里面没有办法通过this调用) 调用构造方法 ...

  5. (转)Java结束线程的三种方法

    背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...

  6. java多线程中的三种特性

    java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...

  7. JAVA写JSON的三种方法,java对象转json数据

    JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...

  8. SuperDiamond在JAVA项目中的三种应用方法实践总结

    SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...

  9. Java结束线程的三种方法(爱奇艺面试)

    线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的.例如在程序中使用线程进行So ...

随机推荐

  1. 自定义View之开关

    资源文件 首先我们需要有两个图片文件,分别是开关的背景和开关的滑块 自定义View 1.写一个类继承View 2.copy该类的全路径名在布局文件使用, 3.找到这个控件,设置初始信息 4.根据需求绘 ...

  2. python迭代器-迭代器取值-for循环-生成器-yield-生成器表达式-常用内置方法-面向过程编程-05

    迭代器 迭代器 迭代: # 更新换代(其实也是重复)的过程,每一次的迭代都必须基于上一次的结果(上一次与这一次之间必须是有关系的) 迭代器: # 迭代取值的工具 为什么用迭代器: # 迭代器提供了一种 ...

  3. Vue的基本使用(四)

    1.refs属性的使用 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset= ...

  4. WGS84坐标与web墨卡托投影坐标转换

    许久没有使用坐标转换,记忆有些模糊了,以后还是会用到,先将WGS84与web墨卡托转换复习一下: 1.84转web墨卡托 //核心公式 平面坐标x = 经度*20037508.34/108 平面坐标y ...

  5. NetCore跨平台桌面框架Avalonia的OSX程序打包

    虽然工作开发语言已经转到了java,但平时仍会用netcore做一些小工具,提升工作效率,但是笔记本换成了Mac,小工具只能做成命令行形式,很是痛苦,迫切需要一个.net跨平台的桌面程序解决方案. 为 ...

  6. C# Winform程序如何使用ClickOnce发布并自动升级(图解)

    有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布关于打包的大家可以看我的文章C# winform程序怎么打包成安装项目(图解)其实打包是打包,发 ...

  7. spark 源码分析之九--Spark RPC剖析之StreamManager和RpcHandler

    StreamManager StreamManager类说明 StreamManager 官方说明如下: The StreamManager is used to fetch individual c ...

  8. 第三章 JavaScript操作Dom对象

    常用的方法: 1.访问节点: 通过Document.getElementByXXX()获得一个指定节点-->再通过以下属性节点访问节点:第一部分:节点属性a:parentNode 返回节点的父节 ...

  9. C++判断图像中一点是否在矩形中

    需要判断出四条之间组成的矩形的范围,其中矩形的边缘可能是倾斜不平行于x或者y轴. 考虑和很久,参考博客http://blog.csdn.net/dapengbusi/article/details/5 ...

  10. Java基础之十五 泛型

    第十五章 泛型 一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大. 在面对对象编程语言中,多态算是一种泛化机 ...