Java生产者消费者的三种实现
Java生产者消费者是最基础的线程同步问题,java岗面试中还是很容易遇到的,之前没写过多线程的代码,面试中被问到很尬啊,面完回来恶补下。在网上查到大概有5种生产者消费者的写法,分别如下。
- 用synchronized对存储加锁,然后用object原生的wait() 和 notify()做同步。
- 用concurrent.locks.Lock,然后用condition的await() 和signal()做同步。
- 直接使用concurrent.BlockingQueue。
- 使用PipedInputStream/PipedOutputStream。
- 使用信号量semaphore。
我的理解,生产者消费者模式,其实只要保证在存储端同一时刻只有一个线程读或写就不会有问题,然后再去考虑线程同步。方法1 2 5都比较类似,都是加锁来限制同一时刻只能有一个读或写。而方法3 4其实是在存储内部去保证读和写的唯一的,最低层肯定还是通过锁机制来实现的,java底层代码都封装好了而已。
我自己尝试写了下前三种,代码如下:
synchronized版本
import java.util.LinkedList;
import java.util.Queue;
public class ProducerAndConsumer {
private final int MAX_LEN = 10;
private Queue<Integer> queue = new LinkedList<Integer>();
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
synchronized (queue) {
while (queue.size() == MAX_LEN) {
queue.notify();
System.out.println("当前队列满");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(1);
queue.notify();
System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
synchronized (queue) {
while (queue.size() == 0) {
queue.notify();
System.out.println("当前队列为空");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
queue.notify();
System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}
lock版实现,使用了condition做线程之间的同步。
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* version 1 doesn't use synchronized to improve performance
*/
public class ProducerAndConsumer1 {
private final int MAX_LEN = 10;
private Queue<Integer> queue = new LinkedList<Integer>();
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
lock.lock();
try {
while (queue.size() == MAX_LEN) {
System.out.println("当前队列满");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(1);
condition.signal();
System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
lock.lock();
try {
while (queue.size() == 0) {
System.out.println("当前队列为空");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
condition.signal();
System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}
BlockingQueue版实现
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ProducerAndConsumer {
private BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(10);
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
try {
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产者生产一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(new Random().nextInt(1000)+500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费一条任务,当前队列长度为" + queue.size());
try {
Thread.sleep(new Random().nextInt(1000)+500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}
版权声明:本文为博主原创文章,转载请注明出处。 博客地址:https://xindoo.blog.csdn.net/
Java生产者消费者的三种实现的更多相关文章
- java实现生产者/消费者的三种方式
package com.wenki.thread; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQue ...
- 基于Java 生产者消费者模式(详细分析)
Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...
- java解析xml的三种方法
java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...
- java中 this 的三种用法
Java中this的三种用法 调用属性 (1)this可以调用本类中的任何成员变量 调用方法(可省略) (2)this调用本类中的成员方法(在main方法里面没有办法通过this调用) 调用构造方法 ...
- (转)Java结束线程的三种方法
背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
- JAVA写JSON的三种方法,java对象转json数据
JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...
- SuperDiamond在JAVA项目中的三种应用方法实践总结
SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...
- Java结束线程的三种方法(爱奇艺面试)
线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的.例如在程序中使用线程进行So ...
随机推荐
- JWT(JSON WEB TOKEN)实例
JWT的工具类 加密解密工具 package top.wintp.crud.util; import com.auth0.jwt.JWTSigner; import com.auth0.jwt.JWT ...
- xutils3 上传文件操作——个人小计
上传文件注意: 使用KeyValue对象进行添加文件操作 int uid = 2; //普通字段的存储 requestParams.addBodyParameter("uid", ...
- java和golang通过protobuf协议相互通信
目录 整体结构说明 protobuf2文件 golang客户端 目录结构 生成pb.go文件 main.go util.go java服务端 目录结构 pom.xml application.yml ...
- cocos creator 小游戏区域截图功能实现
截图是游戏中非常常见的一个功能,在cocos中可以通过摄像机和 RenderTexture 可以快速实现一个截图功能,具体API可参考:https://docs.cocos.com/creator/m ...
- C#编程.函数.参数
详细内容请参见<C#入门经典(第4版)>p101页 1.参数匹配 在调用函数时,必须使参数与函数定义中指定的参数完全匹配,这意味着要匹配参数的类型.个数.和顺序. 注:函数签名由函数的名称 ...
- Java简单公式计算器
最近给公司开发业务代码时,碰到一个场景,简单描述是这样的: 客户要向咱们公司定制一件产品,这个产品呢,有很多属性,那公司得根据这些属性报价呀,怎么报价呢?公司针对某种类型的产品有一个基准价,在同类产品 ...
- C语言编程入门之--第二章编译环境搭建
第二章 编译环境搭建 导读:C语言程序如何工作,首先需要编译链接成可执行文件,然后就可以运行在不同的环境中,这个“环境”的意思就是比如说,电脑,手机,路由器,蓝牙音箱等等智能设备中,其中编译器启到了关 ...
- Office2010安装问题锦集
问题一,每次打开office 2010,都会出现重新配置的对话框. 解决姿势: 大部分搜索到的解决方法大概有2种, 一个是修改注册表,在注册表中这个这个位置增加一个名为NoRereg的32位World ...
- google、谷歌浏览截图
对于前端好用的浏览器---谷歌浏览器(没有插件)截取全屏很难受! 特备是前端,想截图下来,好好的量一下容器之前的尺寸(手动恼火) 对于程序员来说不一定需要插件,有很多大佬应该都知道, 小白记忆不好,每 ...
- Java初中级程序员面试题宝典
Java基础部分 &与&&区别? &和&&都是逻辑运算符,都是判断两边同时真则为真,否则为假:但是&&当第一个条件不成之后,后面的条件都 ...