多线程之生产者-消费者


生产者-消费者模型就是生产者每生产一个资源,消费者消费一个资源,不管生产者或者消费者有多少个。这里模拟用多线程技术实现生产者-消费者模型。


本文以两种方式实现生产者-消费者模型。


1、传统的同步方式,实现多个线程的生产者-消费者模型

这里使用了synchronized对操作共享资源的方法同步,即同一时刻只有一个线程操作共享资源,其他线程处于等待状态,直到当前线程操作完成,然后等待被唤醒。


Producer代码:

package com.deppon.foss.multithred;

/**
 * 
 * <p>生产者</p>
 * @author Stephen
 * @version 1.0
 * @date 2015-4-6
 */
public class Producer implements Runnable {
	
	private Resource resource;
	
	public Producer(Resource resource) {
		this.resource = resource;
	}
	
	@Override
	public void run() {
		while(true){
			resource.put("+商品+");
		}
	}

}

Consumer代码:

package com.deppon.foss.multithred;

/**
 * 
 * <p>消费者</p>
 * @author Stephen
 * @version 1.0
 * @date 2015-4-6
 */
public class Consumer implements Runnable {

	private Resource resource;
	
	public Consumer(Resource resource) {
		this.resource = resource;
	}
	
	@Override
	public void run() {
		while(true){
			resource.take();
		}
	}

}


Resource代码:

代码里面有两个方法:put()生产资源,take()取资源,方法都是同步的。代码里开启了四个线程,两个线程负责生产资源,两个线程负责消费资源。

需要注意的地方:

  • 这里不能if判断,只能用while循环来判断。
  • 这里只能用notifyAll()方法,把所有在等待的线程唤醒,如果用notify()方法,不能保证消费的线程被唤醒。


package com.deppon.foss.multithred;

/**
 * 
 * <p>生产者-消费者案例研究</p>
 * if只判断一次,while重复判断<br/>
 * notify()唤醒先在池中等待的线程,notifyAll()唤醒所有在等待的线程
 * @author Stephen
 * @version 1.0
 * @date 2015-4-6
 */
public class Resource {

	private String name;
	private boolean flag = false;  //标记
	private int count = 0;
	
	/**
	 * 
	 * <p>生产方法</p>
	 * @author Stephen
	 * @version 1.0
	 */
	public synchronized void put(String name){
		while (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				flag = true;
			}
		}
		this.name = name + "--" +(++count);
		System.out.println(Thread.currentThread().getName() + "..生产者.." + this.name);
		flag = true;
		this.notifyAll(); 
	}
	
	/**
	 * 
	 * <p>消费方法</p>
	 * @author Stephen
	 * @version 1.0
	 */
	public synchronized void take(){
		while (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				flag = false;
			}
		}
		System.out.println(Thread.currentThread().getName() + ".......消费者......." + this.name);
		flag = false;
		this.notifyAll();
	}
	
	public static void main(String[] args) {
		Resource resource = new Resource();
		Producer producer = new Producer(resource);
		Consumer consumer = new Consumer(resource);
		new Thread(producer).start();
		new Thread(producer).start();
		new Thread(consumer).start();
		new Thread(consumer).start();
	}
}

运行上述代码,可以看出每生产一个资源就被消费者取走。



2、使用Lock和Condition实现生产者-消费者模型。


Producer代码:

package com.deppon.foss.multithred;

/**
 * 
 * <p>生产者</p>
 * @author Stephen
 * @version 1.0
 * @date 2015-4-6
 */
public class ConditionProducer implements Runnable {
	
	private ConditionResource resource;
	
	public ConditionProducer(ConditionResource resource) {
		this.resource = resource;
	}
	
	@Override
	public void run() {
		while(true){
			resource.put("+商品+");
		}
	}

}


Consumer代码:

package com.deppon.foss.multithred;

/**
 * 
 * <p>消费者</p>
 * @author Stephen, 刘欣雨, 219321
 * @version 1.0
 * @date 2015-4-6
 */
public class ConditionConsumer implements Runnable {

	private ConditionResource resource;
	
	public ConditionConsumer(ConditionResource resource) {
		this.resource = resource;
	}
	
	@Override
	public void run() {
		while(true){
			resource.take();
		}
	}

}

Resource代码:

代码里面有两个方法:put()生产资源,take()取资源。代码里开启了四个线程,两个线程负责生产资源,两个线程负责消费资源。

需要注意的地方:

  • 这里不能if判断,只能用while循环来判断。
  • 这里使用了两个Condition,一个是生产资源的条件,一个是消费资源的条件,这样做效率更高,每次唤醒不用唤醒左右的线程,只需唤醒对象的线程即可。

package com.deppon.foss.multithred;

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

/**
 * 
 * <p>生产者-消费者案例研究,使用Lock和Condition</p>
 * 使用两个Condition,实现细粒度的控制
 * @author Stephen
 * @version 1.0
 * @date 2015-4-6
 */
public class ConditionResource {

	private String name;
	private boolean flag = false;  //标记
	private int count = 0;
	
	private Lock lock = new ReentrantLock();
	private Condition proCondition = lock.newCondition();
	private Condition conCondition = lock.newCondition();
	
	/**
	 * 
	 * <p>生产方法</p>
	 * @author Stephen
	 * @version 1.0
	 */
	public void put(String name){
		lock.lock();
		try {
			while (flag) {
				proCondition.await();
			}
			this.name = name + "--" +(++count);
			System.out.println(Thread.currentThread().getName() + "..生产者.." + this.name);
			flag = true;
			conCondition.signal();
		} catch (InterruptedException e) {
			flag = true;
		} finally {
			lock.unlock();
		}
	}
	
	/**
	 * 
	 * <p>消费方法</p>
	 * @author Stephen
	 * @version 1.0
	 */
	public void take(){
		lock.lock();
		try {
			while (!flag) {
				conCondition.await();
			}
			System.out.println(Thread.currentThread().getName() + ".......消费者......." + this.name);
			flag = false;
			proCondition.signal();
		} catch (InterruptedException e) {
			flag = false;
		} finally {
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		ConditionResource resource = new ConditionResource();
		ConditionProducer producer = new ConditionProducer(resource);
		ConditionConsumer consumer = new ConditionConsumer(resource);
		new Thread(producer).start();
		new Thread(producer).start();
		new Thread(consumer).start();
		new Thread(consumer).start();
	}
}

运行上述代码,可以看出每生产一个资源就被消费者取走。




对上述两种方式进行比较分析后,可以知道,使用Lock和Condition的方式要明显优于使用synchronized,前者减少没次唤醒线程的数量,做到更细粒度的控制,在并发量大的情况下,明显有优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值