生产者与消费者的代码实现,这个套路基本上和上篇文章一个样,所以我就不对代码多做解释了;
之所以写这篇文章是为了介绍ReentrantLock 以及方便后面的一篇采用JDK提供的队列来实现生产者与消费者的代码来与之做比较;
先看输出********************************************************************************
开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...
******************************************************************************************
//餐厅
class Restaurant{
public Food food = null;//餐厅里的食物默认是没有的
public Provider provider = null;
public Consumer comsumer = null;
public void setProvider( Provider provider){
this.provider= provider;
}
public void setConsumer( Consumer consumer){
this.comsumer= consumer;
}
//用单例,保证所有顾客都是在同一家餐厅
private Restaurant() {}
private static final Restaurant restaurant = new Restaurant();
public static Restaurant getInstance(){return restaurant;}
}
//食物提供者(厨师)
class Provider{
//在这家餐厅工作
private Restaurant res = null;
public Provider( Restaurant res ) {
this.res = res;
}
public void fry() throws InterruptedException{//炒菜
while( !Thread.currentThread().isInterrupted() ){
synchronized (this) {
//如果当前还有食物没有被消费完,则继续等待
while( res.food!=null ){
wait();
}
}
synchronized (res.comsumer) {
System.out.println("开始做食物...");
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
res.food= new Food();
System.out.println("食物做完了!...");
//让顾客开始吃食物
res.comsumer.notifyAll();
}
}
}
}
//食物消费者(顾客)
class Consumer{
//在这家餐厅就餐
private Restaurant res = null;
public Consumer( Restaurant res ) {
this.res = res;
}
//吃食物方法
public void eat() throws InterruptedException{
while( !Thread.currentThread().isInterrupted() ){
synchronized (this) {
//如果当前没有食物可用,则继续等待
while(res.food==null){
wait();
}
}
synchronized (res.provider) {
System.out.println("开始吃食物...");
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));//吃食物时间
res.food=null;
System.out.println("食物吃完了!...");
//让厨师继续做食物
res.provider.notifyAll();
}
}
}
}
//经典生产者与消费者演示(不采用队列的普通实现)
//考虑这样一个场景:顾客在餐厅点菜后,厨师开始炒菜,厨师炒完菜后送给顾客吃,顾客吃完又通知厨师炒菜...周而复始...
//这个场景就是典型的生产者(厨师)与消费者(顾客)
public static void producer(){
ExecutorService exec = Executors.newCachedThreadPool();
Restaurant res = Restaurant.getInstance();
final Consumer consumer = new Consumer(res);
final Provider provider = new Provider(res);
res.setProvider(provider);
res.setConsumer(consumer);
//启动顾客线程,顾客要消费
exec.execute(new Runnable() {
public void run() {
try {
consumer.eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//启动厨师线程,厨师要生产
exec.execute(new Runnable() {
public void run() {
try {
provider.fry();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
Ok,不做代码解释,和上篇一样,接下来我们主要看下怎么利用ReentrantLock来实现生产者与消费者,让我们修改下代码:
//餐厅
class Restaurant{
public Food food = null;//餐厅里的食物默认是没有的
public Provider provider = null;
public Consumer comsumer = null;
// 演示变体,利用Lock来进行协作,需要增加两把锁以及两个条件
public ReentrantLock providerLock = new ReentrantLock();
public ReentrantLock consumerLock = new ReentrantLock();
public Condition providerCondition = providerLock.newCondition();
public Condition consumerCondition = consumerLock.newCondition();
public void setProvider( Provider provider){
this.provider= provider;
}
public void setConsumer( Consumer consumer){
this.comsumer= consumer;
}
//用单例,保证所有顾客都是在同一家餐厅
private Restaurant() {}
private static final Restaurant restaurant = new Restaurant();
public static Restaurant getInstance(){return restaurant;}
}
//食物提供者(厨师)
class Provider{
//在这家餐厅工作
private Restaurant res = null;
public Provider( Restaurant res ) {
this.res = res;
}
public void fry() throws InterruptedException{//炒菜
while( !Thread.currentThread().isInterrupted() ){
// 开始演示使用Lock来进行协作
res.providerLock.lock();
while( res.food!=null ){
res.providerCondition.await();
}
res.providerLock.unlock();
res.consumerLock.lock();
System.out.println("开始做食物...");
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
res.food= new Food();
System.out.println("食物做完了!...");
//让顾客开始吃食物
res.consumerCondition.signalAll();
res.consumerLock.unlock();
}
}
}
//食物消费者(顾客)
class Consumer{
//在这家餐厅就餐
private Restaurant res = null;
public Consumer( Restaurant res ) {
this.res = res;
}
//吃食物方法
public void eat() throws InterruptedException{
while( !Thread.currentThread().isInterrupted() ){
// 开始演示使用Lock来进行协作
res.consumerLock.lock();
while(res.food==null){
res.consumerCondition.await();
}
res.consumerLock.unlock();
res.providerLock.lock();
System.out.println("开始吃食物...");
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));//吃食物时间
res.food=null;
System.out.println("食物吃完了!...");
//让厨师继续做食物
res.providerCondition.signalAll();
res.providerLock.unlock();
}
}
}
稍作解释: 这里主要利用ReentrantLock的 lock()与unLock() 来进行加解锁 , 通过调用它的newCondition()方法来获得一个对象监视器,该监视器拥有await(0与signalAll()等方法, 和Object的wait()以及notifyALL()的功能是一样的!
多线程的基础篇到这里就结束了,你要知道的是,在实际工作中,肯定是不需要你自己来写什么notify和wait之类的,这太困难了,得写一堆难看的代码,那么接下来,我们就来学学怎么使用JDK中的一些好用的工具类,来帮助我们轻而易举的实现复杂的多线程编程问题;