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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值