生产者-消费者模型就是生产者每生产一个资源,消费者消费一个资源,不管生产者或者消费者有多少个。这里模拟用多线程技术实现生产者-消费者模型。
本文以两种方式实现生产者-消费者模型。
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,前者减少没次唤醒线程的数量,做到更细粒度的控制,在并发量大的情况下,明显有优势。