`
y13872888163
  • 浏览: 16977 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

JAVA消费者与生产者模型的几个不同实现

 
阅读更多

       java的生产者与消费者模型对与理解JAVA的锁机制,线程安全和并发编程来说是一个比较经典的例子,下面就将我遇到过的几种不同的实现跟大家分享一下。


1.使用synchronized关键字

         synchronized来 加同步锁,保证线程安全,synchronized锁自1.6后做了很大的优化,对于一般情况下的同步,用此锁已经足已应付。

public class ProducerAndConsumer {
	public static void main(String[] args) {
		SyncStack ss = new SyncStack();
		// 生产者线程
		Thread t1 = new Thread(new Producer(ss));
		// 消费者线程
		Thread t2 = new Thread(new Consumer(ss));
		t1.start();
		t2.start();
	}
}

class Entity {
	int id;

	Entity(int id) {
		this.id = id;
	}

	public String toString() {
		return " entity :" + id;
	}
}

class SyncStack {

	int index = 0;

	Entity[] arrWT = new Entity[6];

	public synchronized void push(Entity wt) {
		if (index == arrWT.length)
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		this.notify();
		arrWT[index] = wt;
		index++;
	}

	public synchronized void pop(Entity wt) {
		if (index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		index--;
	}
}

class Producer implements Runnable {
	SyncStack ss = null;

	Producer(SyncStack ss) {
		this.ss = ss;
	}

	public void run() {
		for (int i = 0; i < 20; i++) {
			Entity e = new Entity(i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			ss.push(e);
			System.out.println("生产了" + e);
		}
	}
}

class Consumer implements Runnable {
	SyncStack ss = null;

	public Consumer(SyncStack ss) {
		this.ss = ss;
	}

	public void run() {
		for (int i = 0; i < 20; i++) {
			Entity wt = new Entity(i);
			try {
				// 随机休眠一段时间
				Thread.sleep((int) (Math.random() * 3000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			ss.pop(wt);
			System.out.println("消费了" + wt);
		}
	}
}


     运行结果 :

   

生产了 entity :1
消费了 entity :1
生产了 entity :2
生产了 entity :3
消费了 entity :2
生产了 entity :4
生产了 entity :5
消费了 entity :3

 2.使用ReentrantLock和Condition

<!-- Generated by javadoc (build 1.6.0-beta2) on Fri Mar 09 12:53:21 CST 2007 -->

<noscript></noscript>

          ReentrantLock是可重入锁,自JDK1.5添加,  一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

          Condition 条件(也称为条件队列条件变量,它 替代了 Object 监视器方法的使用。(具体自己参考API)

  

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ProducerAndConsumer {
	final Lock lock = new ReentrantLock();   //可重入锁
	final Condition notFull = lock.newCondition();    //非满条件
	final Condition notEmpty = lock.newCondition();  //非空条件
	
	final Object[] items = new Object[100];
	int putptr , takeptr , count;
	
	public void put(Object o) throws InterruptedException{
		lock.lock();      //锁定操作,保证线程安全
		try{
			while(count == items.length){
				notFull.wait();
			}
			items[putptr] = o;
			if(++putptr == items.length)
				putptr = 0;
			
			++count;
			notEmpty.signal();
			
		}finally{
				lock.unlock();
				
		}
	}
	
	public Object take() throws InterruptedException{
		lock.lock();    //
		try {
			while(count == 0)
				notEmpty.await();
			Object o = items[takeptr];
			if(takeptr == items.length)
				takeptr = 0;
			--count;
			notFull.signal();
			return o;
		} finally{
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		final ProducerAndConsumer pac = new ProducerAndConsumer();
		//模拟消费者
                new Thread(new Runnable(){
			public void run() {
				try {
					for(;;){
						pac.take();
						System.out.println(Thread.currentThread().getName());
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		//模拟生产者
		new Thread(new Runnable(){
			public void run() {
				try {
					for(int i=0;i<10;i++){
						Object o = new Object();
						pac.put(o);
						System.out.println(Thread.currentThread().getName());
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
}


3.使用semaphore

<!-- Generated by javadoc (build 1.6.0-beta2) on Fri Mar 09 12:53:11 CST 2007 -->

<noscript></noscript>

         semaphore   一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个relase  添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目.

import java.util.concurrent.Semaphore;

public class TestSemaphore {

	final static BoundBuffer buffer = new BoundBuffer();

	public static void main(String[] args) {
		// 各启动3个线程
		for (int i = 0; i < 3; i++) {
			new Thread(new Producer()).start();
			new Thread(new Consumer()).start();
		}
	}

	static class BoundBuffer {
		final Semaphore notFull = new Semaphore(10);

		final Semaphore notEmpty = new Semaphore(0);

		// 传入参数为1,为了模拟一个互斥锁
		final Semaphore mutex = new Semaphore(1);

		Object[] items = new Object[10];

		int putptr, takeptr;

		static int count, put, take;

		public void put(Object o) {

			try {
				// 先拿到put的许可,在拿互斥锁;同时减少一个许可
				notFull.acquire();
				// 加互斥锁,保证线程安全
				mutex.acquire();
				items[putptr] = o;
				if (++putptr == items.length) {
					putptr = 0;
				}
				++count;
				++put;
				System.out.println("共生产了 " + put + " 个,还剩 " + count + " 个");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				// 释放互斥锁
				mutex.release();
				// 注意此处是notEmpty.release(),该许可+1,表示新增了一个产品
				// 消费者线程还可以来消费
				notEmpty.release();
			}
		}

		public Object take() {
			try {
				notEmpty.acquire();
				mutex.acquire();
				Object o = items[takeptr];
				if (++takeptr == items.length)
					takeptr = 0;
				--count;
				++take;
				System.out.println("共消费了 " + take + " 个,还剩 " + count + " 个");
				return o;
			} catch (InterruptedException e) {
				e.printStackTrace();
				return null;
			} finally {
				mutex.release();
				// 此处notFull.release(),表示新增了一个put的许可,生产者可以继续put
				notFull.release();
			}
		}
	}

	static class Consumer implements Runnable {

		public void run() {
			while (true) {
				buffer.take();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	static class Producer implements Runnable {

		public void run() {
			while (true) {
				Object o = new Object();
				buffer.put(o);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}

	}
}

 运行结果 :

 

共生产了 1 个,还剩 1 个
共生产了 2 个,还剩 2 个
共生产了 3 个,还剩 3 个
共消费了 1 个,还剩 2 个
共消费了 2 个,还剩 1 个
共消费了 3 个,还剩 0 个
共生产了 4 个,还剩 1 个
共生产了 5 个,还剩 2 个
.......

 

还有其他的一些实现方式,欢迎大家分享



0
3
分享到:
评论

相关推荐

    模拟仿真“生产者-消费者”问题的解决过程及方法

    本课程设计的目的是通过设计一个消费者进程与生产者进程的同步模拟系统,认识进程间的同步机制生产者消费者问题是一个著名的进程...这是一个用Eclipse为工具、java为编程语言而实现模拟消费者进程与生产者进程的同步。

    java初学者必看

    11.5.3 运行生产者/消费者 11.6 死锁 11.7 本章习题 第12章 异常处理 12.1 异常的概念 12.2 异常的基本样式 12.3 Java异常类 12.3.1 异常类层次结构 12.3.2 异常处理方法 12.4 异常捕获 12.4.1 异常捕获...

    JAVA上百实例源码以及开源项目源代码

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    JAVA面试题最全集

    12.synchronized (生产者和消费) 13.String 和 StringBuffer 14.Serializable 15.MVC (Struts的工作流程) 16.什么是MDA 17.tcp与udp的区别 18.链表与散列表和数组的区别 19.堆和栈的区别 20.ejb的分类及...

    Spring 实现远程访问详解——jms和activemq

    前几章我们分别利用spring rmi、httpinvoker、httpclient、webservice技术实现不同服务器间的远程访问。本章我将通过spring jms和activemq实现单Web项目服务器间异步访问和多Web项目服务器间异步访问。 一. 简介 1. ...

    word源码java-rabbitmq-tutorial-java:RabbitMQ官方教程的翻译和说明--Java版

    生产者和RabbitMQ服务器建立连接和通道,声明路由器,同时为消息设置路由键,这样,所有的消息就会以特定的路由键发给路由器,具体路由器会发送到哪个或哪几个队列,生产者在大部分场景中都不知道。(1个路由器,但...

    实战Java高并发程序设计(第2版)PPT模板.pptx

    5并行模式与算法 5.1探讨单例模式 5.3生产者-消费者模式 5.5future模式 5.2不变模式 5.4高性能的生产者-消费者模式:无锁的实现 5.6并行流水线 01 02 03 04 05 06 实战Java高并发程序设计(第2版)PPT模板全文共25...

    JAVA ORACLE数据库资料讲解

    除了偶尔少量加入几个新的实体类型外,在企业经营方向不发生改变的前提下,这些实体类型及其属性之间的内在联系是不会变化的,变化的只是实体的属性值。如同机场航班信息牌上的数据一样,数据的格式一般是不变的,而...

    merkle-tree:Java中的默克尔树实现

    有几种方法可以做到这一点,但由于我们的数据事件已经附加了一个签名(一个 SHA1 散列),我决定做检查点的一个有用的方法基本上是保留一个散列的散列。 可以使用来做到这一点,其中保留了每个数据元素的散列链,...

    Java开发技术大全 电子版

    8.4.4生产者-消费者问题实例284 8.5本章小结287 第9章运行时类型识别288 9.1RTTI的作用288 9.2用Class类来加载对象289 9.3使用getClass()方法获取类信息290 9.4使用类标记292 9.5使用关键字instanceof判断...

    外文翻译 stus MVC

    This article introduces Struts, a Model-View-Controller implementation that uses servlets and JavaServer Pages (JSP) technology. Struts can help you control change in your Web project and promote ...

    javaSE代码实例

    16.4.5 “生产者-消费者”案例的实际运行 365 16.4.6 notify方法的使用 366 16.4.7 同步的语句块 367 16.4.8 线程的死锁 369 16.4.9 防止错误的使用wait、notify、notifyAll方法 371 16.5 获取当前正在...

    leetcode下载-LeetCode-Nowcoder-DataStruct:记录日常刷题与数据结构

    这个包下面的东西都是与并发编程相关的东西,比如阻塞队列实现生产者消费者模型,CAS,n种单例模式,线程交替打印,线程通信,读写锁,信号量,countdLaunch,circleBarrier等等 五. LeetCode 记录力扣刷题 由于本人不经常在...

    TongWeb嵌入式版本用户手册-7.0.E.5

    TongWeb 嵌入式版是同时支持 Java EE 企业级标准与 React 响应编程标准的嵌入式应用 服务器,且支持基于算法模型的网关服务,并通过集成 Spring Boot、Spring Cloud 框架进行 使用。 TongWeb 嵌入式版 Web 容器需要...

    新版Android开发教程.rar

    ANDROID 的推出后可能影响的产业包括移动电信业,软件开发业,手机制造业,在以消费者为核心的状 态 。 对消费者的影响 � 高档手机选择面增加。 � A ndroid 在设计初期就考虑了与现其有业务的融合,改变以往从...

    汪文君高并发编程实战视频资源全集

    │ 高并发编程第一阶段28讲、线程生产者消费者的综合实战结合Java8语法.mp4 │ 高并发编程第一阶段29讲、如何实现一个自己的显式锁Lock精讲上.mp4 │ 高并发编程第一阶段30讲、如何实现一个自己的显式锁Lock精讲...

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第一阶段28讲、线程生产者消费者的综合实战结合Java8语法.mp4 │ 高并发编程第一阶段29讲、如何实现一个自己的显式锁Lock精讲上.mp4 │ 高并发编程第一阶段30讲、如何实现一个自己的显式锁Lock精讲...

    C#微软培训资料

    9.2 对象的模型技术 .103 9.3 面向对象的分析 .105 9.4 面向对象的设计 .107 9.5 小 结 .110 第十章 类 .112 10.1 类 的 声 明 .112 10.2 类 的 成 员 .113 10.3 构造函数和析构函数 .119 10.4 小 ...

Global site tag (gtag.js) - Google Analytics