生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。

使用synchronized关键字实现线程同步

在使用wait()和notifyAll()方法时,应注意将wait()方法放入循环中,否则会产生虚假唤醒问题。

/**
* Created by 吴海飞 on 2017-1-23.
*/
public class TestProductAndConsumer {
public static void main(String[] args){
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(pro,"生产者A").start();
new Thread(consumer,"消费者B").start();
}
} /**
* 店员,可以进货与销售货物
*/
class Clerk{ private int product = 0; /**
* 进货的方法
*/
public synchronized void get(){
while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("产品已满!"); try {
this.wait();//等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + ++product);
this.notifyAll();//唤醒线程
} /**
* 销售的方法
*/
public synchronized void sale(){
while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
System.out.println("缺货……");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":"+ --product);
this.notifyAll();
}
} /**
* 生产者
*/
class Productor implements Runnable{ private Clerk clerk; public Productor(Clerk clerk){
this.clerk = clerk;
} @Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
} /**
* 消费者
*/
class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){
this.clerk = clerk;
} @Override
public void run() {
for (int i = 0; i < 10; i++){
clerk.sale();
}
}
}

使用同步锁实现线程同步问题

使用同步锁时应注意lock()与unlock()方法的同步使用。


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 使用ReentrantLock实现生产者消费者问题
* Created by 吴海飞 on 2017-1-23.
*/
public class TestReentrantLock {
public static void main(String[] args){
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer consumer = new Consumer(clerk); new Thread(pro,"生产者A").start();
new Thread(consumer,"消费者B").start();
new Thread(pro,"生产者C").start();
new Thread(consumer,"消费者D").start();
}
} class Clerk{
private Lock lock = new ReentrantLock();//获取同步锁
private Condition condition = lock.newCondition();
private int product = 0; /**
* 进货的方法
*/ public void get(){
lock.lock();//打开锁
try{
while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("产品已满!");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + ++product);
condition.signalAll();
}finally {
lock.unlock();//关闭锁
} } /**
* 销售的方法
*/ public void sale(){
lock.lock();//加锁
try {
while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
System.out.println("缺货……");
try {
condition.await();//等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":"+ --product);
condition.signalAll();//唤醒等待
}finally {
lock.unlock();//释放锁
} }
} /**
* 生产者
*/ class Productor implements Runnable{ private Clerk clerk; public Productor(Clerk clerk){
this.clerk = clerk;
} @Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
} /**
* 消费者
*/ class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){
this.clerk = clerk;
} @Override
public void run() {
for (int i = 0; i < 10; i++){
clerk.sale();
}
}
}

java实现生产者消费者模式的更多相关文章

  1. Java设计模式—生产者消费者模式(阻塞队列实现)

    生产者消费者模式是并发.多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据.这篇文章我们来看看什么是生产者消费者模式,这个问 ...

  2. java多线程 生产者消费者模式

    package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...

  3. 关于java中生产者消费者模式的理解

    在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify() ...

  4. java 实现生产者-消费者模式

    生产和消费者模式有很多种,现在介绍几种常见的方式 wait/notify实现生产和消费者模式 1.使用wait/notify实现生产和消费者模式: public class Depot { // 实际 ...

  5. java——利用生产者消费者模式思想实现简易版handler机制

    参考教程:http://www.sohu.com/a/237792762_659256 首先说一下这里面涉及到的线程: 1.mainLooper: 这个线程可以理解为消费者线程,里面运行了一个死循环, ...

  6. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  7. Java 生产者消费者模式详细分析

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  8. java ReentrantLock结合条件队列 实现生产者-消费者模式 以及ReentratLock和Synchronized对比

    package reentrantlock; import java.util.ArrayList; public class ProviderAndConsumerTest { static Pro ...

  9. Java 学习笔记 使用并发包ReentrantLock简化生产者消费者模式代码

    说明 ReentrantLock是java官方的一个线程锁类,ReentarntLock实现了Lock的接口 我们只需要使用这个,就可以不用使用synchronized同步关键字以及对应的notify ...

随机推荐

  1. Eclipse之Web工程探究以及格式化

    1. 关于部署 只要配置了Web Deployment Assembly,可以不需要手工拷贝引用jar到/WEB-INF/lib里面了,之前失败是因为引用工程的output路径有问题导致的,修改完成后 ...

  2. CF 85E Guard Towers——二分图染色

    题目:http://codeforces.com/contest/85/problem/E 当然是二分.然后连一个图,染色判断是不是二分图即可.方案数就是2^(连通块个数). 别真的连边!不然时间空间 ...

  3. CentOS7.2 GitLab部署

    1.使用安装包的方式安装gitlab # vim /etc/yum.repos.d/gitlib.repo [gitlab-ce] name=gitlab-ce baseurl=http://mirr ...

  4. 自己写的工具:把Evernote(印象笔记)的笔记导入到博客(Blog)中

    Evernote是个强大的工具, 这个伴随了我快4年的工具让我积累好多笔记.但是,如何把evernote(印象笔记)中的笔记发布到博客中呢? 自己空闲时候用python 3写了个工具Evernote2 ...

  5. Qt中如何用QImage::Format_Indexed8表示灰度图

    QImage *qi = new QImage(data_ptr, width, height, QImage::Format_Indexed8); QVector<QRgb> grayT ...

  6. 机器学习:评价分类结果(Precision - Recall 的平衡、P - R 曲线)

    一.Precision - Recall 的平衡 1)基础理论 调整阈值的大小,可以调节精准率和召回率的比重: 阈值:threshold,分类边界值,score > threshold 时分类为 ...

  7. 第 十五 课 Go 语言范围(Range)

    Go 语言中 range 关键字用于 for 循环中迭代数组(array).切片(slice).通道(channel)或集合(map)的元素 package main import "fmt ...

  8. 【render】partial及其局部变量

    原文:http://www.cnblogs.com/lwm-1988/archive/2011/09/13/2175041.html 1. partial 1.1 把partial作为view的一部分 ...

  9. php学习之try catch

    PHP 5 添加了类似于其它语言的异常处理模块.在 PHP 代码中所产生的异常可被 throw语句抛出并被 catch 语句捕获.(注:一定要先抛才能获取) 需要进行异常处理的代码都必须放入 try ...

  10. ffmpeg部分编译选项

    -enable-neon  (如果使用了arm公司提供的neon加速技术,则可以并行的读取多个元素.参考网址:http://www.cnblogs.com/hrlnw/p/3723072.html) ...