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 个
.......
还有其他的一些实现方式,欢迎大家分享
分享到:
相关推荐
生产者-消费者模型的实现涉及以下几个关键点: - **同步控制**:确保生产者不会在缓冲区满时继续生产,而消费者在缓冲区为空时不进行消费。 - **线程通信**:生产者生产完产品后通知消费者,消费者消费完产品后通知...
生产者消费者模型是一种经典的线程同步问题,它模拟了实际生活中的生产过程和消费过程,使得生产者线程可以将数据生产出来,而消费者线程则负责消耗这些数据,两者之间通过共享数据结构进行协同工作。 生产者消费者...
在Java编程中,生产者消费者模式是一种典型的多线程协作模型,用于解决系统资源供需不平衡的问题。这个模式的核心思想是将生产数据和消费数据的过程解耦,使得生产者可以独立地生产数据,而消费者可以独立地消费数据...
在这个特定的"多个消费者生产者模型"中,有几个关键点需要注意: 1. **多生产者**:系统中有多个生产者线程,每个线程可以独立地生成产品。为了防止冲突,生产者之间需要同步,确保它们不会同时向队列中添加产品,...
Java线程安全与生产者消费者模型是多线程编程中的两个重要概念,它们在并发处理中扮演着关键角色。在Java中,线程安全是指一个类或者方法在多线程环境下能够正确地处理数据,避免数据的不一致性或竞态条件。而生产者...
在Java编程领域,"生产者与消费者"模式是一种常见的多线程问题解决方案,它涉及到并发编程和线程协作。在这个模式中,生产者负责创建资源,而消费者则负责消费这些资源。这种模式常用于实现缓存、队列和其他数据结构...
在这个生产者消费者项目中,主要涉及以下几个关键知识点: 1. **线程间通信**:生产者和消费者之间需要通过某种方式通信,以告知对方何时可以生产或消费。Java提供了`wait()`、`notify()`和`notifyAll()`方法来实现...
- **分布式系统**:在分布式系统中,不同节点之间的通信也可以采用生产者与消费者模型来实现数据交换。 #### 三、实验目的与意义 通过本次实验,学生将能够掌握以下技能: 1. **理解生产者与消费者模型的基本原理...
生产者/消费者模型通常包括以下几个关键组件: 1. **缓冲区**:生产者生产的商品存储的地方,消费者从中取出商品。在Java中,我们可以使用`ArrayBlockingQueue`、`LinkedBlockingQueue`等类型的`BlockingQueue`作为...
为了解决生产者和消费者之间的同步和通信问题,Java提供了几种不同的实现方式,包括synchronized关键字、Condition接口、Lock接口以及信号量(Semaphore)和阻塞队列(BlockingQueue)。 ### 1. synchronized关键字...
本课程设计的目的是通过设计一个消费者进程与生产者进程的同步模拟系统,认识进程间的同步机制生产者消费者问题是一个著名的进程...这是一个用Eclipse为工具、java为编程语言而实现模拟消费者进程与生产者进程的同步。
Java中的`BlockingQueue`接口提供了几个实现类,如`ArrayBlockingQueue`、`LinkedBlockingQueue`和`PriorityBlockingQueue`等,它们都实现了线程安全的队列操作。生产者将数据放入队列,消费者从队列中取出数据,...
在描述中提到的链接(),博主分享了一个关于多线程生产者与消费者模式的具体实现案例。虽然具体代码没有给出,但我们可以根据常见的实现方式来解析这个模式。 1. **共享数据结构**:在这个模式中,通常会有一个...
### Java生产者-消费者模式概述 生产者-消费者模式是多线程编程中的一种经典模式,它通过共享缓冲区来协调多个线程之间的交互:一组线程(生产者)负责向缓冲区添加数据,而另一组线程(消费者)则从缓冲区读取并...
综上所述,Java生产者消费者问题的解决主要依赖于`BlockingQueue`等并发工具,通过合理的线程同步和协作,实现高效的数据处理。理解并熟练运用这些工具,能够帮助开发者构建更加稳定、高效的多线程应用程序。
在Java编程中,线程的生产者与消费者问题是多线程同步的一个典型应用场景。这个问题源自现实世界中的生产流水线,其中生产者负责制造产品,而消费者则负责消耗这些产品。在计算机系统中,生产者可以是生成数据的线程...
生产者消费者问题是多进程处理中的一个经典模型,用于展示如何有效地共享有限资源。在Linux环境下,我们可以利用其强大的多进程支持来解决这个问题。 生产者消费者问题是这样的:有一个有限大小的缓冲区,生产者...
在本篇文章中,我们将重点探讨使用Java语言实现生产者与消费者问题的几种方法。 #### 二、生产者与消费者问题描述 在一个典型的生产者与消费者模型中,存在两个角色:生产者和消费者。生产者负责生成数据并将这些...
操作系统中的“生产者和消费者问题”是一个经典的多线程同步问题,主要涉及到进程通信和资源管理。在这个实验中,我们采用Java语言来实现,因为Java提供了丰富的并发控制机制,如synchronized关键字和wait()、notify...
6. **程序设计与实现**:实验报告中会包含具体的程序设计和实现细节,如使用C、C++或Java等语言实现消费者和生产者的线程,以及如何通过系统调用来实现同步和互斥。 7. **测试与分析**:实验报告还会包括对程序的...