多线程之生产者-消费者

来源:互联网 发布:芒果店长软件下载 编辑:程序博客网 时间:2024/05/22 12:56


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


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


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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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,前者减少没次唤醒线程的数量,做到更细粒度的控制,在并发量大的情况下,明显有优势。

0 0