——- android培训、java培训、期待与您交流! ———-
在JDK1.5之前,解决生产者和消费者问题,
用的是synchronized同步+while+notify();
但是这种方法很不安全,很容易让线程全部陷入无限等待状态。
于是我们改用notiyfyAll();来解决。
这样虽然解决了安全问题,但还是存在不足和安全隐患。
notifyAll方法唤醒了线程池中全部的线程,
这并不是我们想要的!
而且,同步套同步很容易发生死锁!
在JDK1.5中提供了显示的锁机制,完美的解决了上述问题。
它既可以做到只唤醒对方线程,而不唤醒己方线程,
又能够让一个锁绑定多个对象!
下面我们首先来看看JDK1.5新特性吧!
还是用2个生产者线程和2个消费者线程来展示。
步骤:
1 查阅API,找到Condition接口和Lock接口
2 定义资源类
3 定义生产者类
4 定义消费者类
5 定义测试类
6 导包
7 检查安全问题
8 测试
9 分析总结
import java.util.concurrent.locks.*;
//一、定义资源类
class Resource
{
private String name;//商品名称
private int count = 1;//商品编号
private boolean flag = false;//资源监视器
private Lock lock = new ReentrantLock();//建立一个锁对象,注意这里只有一把锁。注意,Lock是接口,不可以直接创建对象
private Condition condition_Pro = lock.newCondition();//建立与lock实例一起使用的Condition实例,生产者使用
private Condition condition_Con = lock.newCondition();//建立与lock实例一起使用的Condition实例,消费者使用
//设置商品名称,商品编号自增,并打印设置结果
public void set(String name)throws InterruptedException
{
lock.lock();//生产者线程获取锁。替换原来的synchronized
try
{
while(flag)//当资源监视器为true时,生产者线程等待
condition_Pro.await();//生产者线程等待,并throws InterruptedException
this.name = name;//获取商品名称
System.out.println(Thread.currentThread().getName()+"是生产者线程,生产的商品名称为:"+name+"商品编号为:"+count);
count++;//商品编号自增
flag = true;//把资源监视器改为true
condition_Con.signal();//只唤醒消费者线程
}
finally
{
lock.unlock();//一定要释放锁
}
}
//取出商品,并展示所取出的商品编号
public void get()throws InterruptedException
{
lock.lock();//消费者线程获取锁
try
{
while(!flag)//如果资源监视器为false,消费者线程等待,并抛出InterruptedException
condition_Con.await();
System.out.println(Thread.currentThread().getName()+"是消费者线程,消费的商品名称为:"+name+"商品编号为:......."+count);
flag = false;//把资源监视器改为false
condition_Pro.signal();//只唤醒生产者线程
}
finally
{
lock.unlock();//一定要释放锁
}
}
}
//二、定义生产者类
class Producer implements Runnable
{
private Resource r;//引用Resource类型变量r
//重载构造函数,避免建立多个对象
Producer(Resource r)
{
this.r = r;
}
//覆盖run方法
public void run()
{
try
{
while(true)//让生产者一直在生产
r.set("商品");
}
catch (InterruptedException e)
{
//暂不处理,以利于观察结果
}
}
}
//三、定义消费者类
class Consumer implements Runnable
{
private Resource r;//引用Resource类型变量r
//重载构造函数,和生产者线程使用同一资源对象
Consumer(Resource r)
{
this.r =r;
}
//覆盖run方法
public void run()
{
try
{
while(true)//让消费者一直取商品
r.get();
}
catch (InterruptedException e)
{
//暂不处理,方便观察
}
}
}
//四、定义测试类
class MyProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();//建立资源
Producer p = new Producer(r);//建立生产者
Consumer c= new Consumer(r);//建立消费者
Thread tp1 = new Thread(p);//建立生产者线程1
Thread tp2 = new Thread(p);//建立生产者线程2
Thread tp3 = new Thread(p);//建立生产者线程3
Thread tc1 = new Thread(c);//建立消费者线程1
Thread tc2 = new Thread(c);//建立消费者线程2
Thread tc3 = new Thread(c);//建立消费者线程3
tp1.start();//启动生产者线程1
tp2.start();//启动生产者线程2
tp3.start();//启动生产者线程3
tc1.start();//启动消费者线程1
tc2.start();//启动消费者线程2
tc3.start();//启动生产者线程3
}
}
运行结果显示正常!
JDK1.5定义了显示的锁机制
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。
将同步操作synchronized替换成了Lock接口
将object中的wait,notify,notifyAll,替换成了Condition对象
在本示例中,实现了只唤醒对方线程,而不会唤醒己方线程。
实现了一个锁lock绑定了两个对象condition_Pro和condition_Con。
注意:
lock和condition都是接口,不可以直接创建对象。
在这里创建Lock对象利用了ReentrantLock类
创建condition对象利用了ReentrantLock类中的newCondition方法。
ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用synchronized 方法和语句
所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
黑马程序员_日记18_Java多线程(八)--生产者消费者问题JDK1.5特性
原文地址:http://blog.csdn.net/itheima_1llt/article/details/44753591