在多线程安全中,使用较多的例子是生产者和消费者模型。
在这个模型中,生产者和消费者是两个独立的线程,但是他们操作的资源的共享的,生产者生产产品,消费者消费产品。假设资源用一个对象来抽象,该对象的set()和out()方法对应生产和消费,那么为了保证多线程安全,每次只能有一个生产者线程生产产品,即只有一个生产者线程可以调用set()函数,同样,每次只能有一个消费者消费产品,即只有一个消费者线程能调用out()函数,所以要加入同步机制,使用synchronized构造同步函数,或者使用jdk1.5之后的新特性,使用java.util.concurrent.locks包中的ReentrantLock和Condition来实现。
Lock和Condition都是接口,Lock接口的方法比如lock()和unlock()代替了synchronized,Condition代替了Object监视器方法的使用。Condition子类对象是通过Lock的newCondiiton()产生的。Condition中有await()、signal()、signalAll()方法,分别代替Object中的wait()、notify()、notifyAll()。
新旧特性对比:
1)Lock的lock()和unlock()可以显式地加锁和解锁,而synchronized关键字并不能显式的加解锁。
2)旧特性中,notify()和wait()必须对应一个锁才能进行唤醒操作,synchronized只对应一个锁,但是新特性中,一个Lock可以对应多个锁,可以创建多个监视器,每个监视器都可以进行线程的等待和唤醒操作,更灵活。
代码:
/*
* 实现消费者和生产者模式
* */
import java.util.concurrent.locks.*;
//共享资源,即商品
class Resource{
private String name;//商品名
private int count;//商品的个数
boolean flag;//代表是否有商品,如果是true,才可以消费,如果是false,才可以生产
Resource(String name){
this.name = name;
}
/*
//这里使用的是jdk的旧特性
//生产商品
//由于商品是生产和消费两个线程的共享数据,所以需要同步才能避免多线程安全问题,所以对于生产和消费过程,每次都只能有一个线程参与,所以将生产和消费过程都进行同步处理
public synchronized void set(String name)throws Exception{
while(flag){
try{
wait();//该线程阻塞等待,会抛出异常InterruptedException
}
catch(Exception e){
}
}
this.name = name+"----------"+(++count);
System.out.println(Thread.currentThread().getName()+"生产::"+this.name);
flag = true;
notifyAll();//唤醒消费者线程,并且防止所有线程都处于等待状态
}
//消费商品
//同生产商品线程,每次只能有一个线程进行消费,否则会出现冲突,因此消费过程也需要进行同步处理
public synchronized void out()throws Exception{
while(!flag){
try{
wait();
}
catch(Exception e){
}
}
System.out.println(Thread.currentThread().getName()+"消费::::"+name);
flag = false;
notifyAll();//唤醒生产者线程,并且防止所有线程都处于等待状态
}
*/
//使用jdk1.5之后的新特性
//java.uti.concurrent.locks包中,有新特性下的多线程操作
//新特性下,Lock的lock()和unlock()方法代替了synchronized方法
//由Condition接口对象调用await()、signal()、signalAll(),代替锁(对象)调用的wait()、notify()、notifyAll()
private ReentrantLock lock = new ReentrantLock();
private Condition con_pro = lock.newCondition();//监视器,监视生产者
private Condition con_con = lock.newCondition();//监视器,监视消费者
//生产商品
public void set(String name)throws InterruptedException{
//加锁
lock.lock();
try{
while(flag){
//有产品,此时不能生产
con_pro.await();//会抛异常InterruptedException
}
this.name = name+"------"+(++count);
System.out.println(Thread.currentThread().getName()+"生产::"+this.name);
flag = true;//此时有商品
con_con.signal();//唤醒消费者线程
}
finally{
//关闭资源
lock.unlock();
}
}
//消费商品
public void out()throws InterruptedException{
//加锁
lock.lock();
try{
while(!flag){
con_con.await();//此时没有商品,所以消费者等待
}
System.out.println(Thread.currentThread().getName()+"消费:::::"+name);
flag = false;
con_pro.signal();//唤醒生产者
}
finally{
lock.unlock();//释放资源
}
}
}
//生产者线程
class ProducerThread implements Runnable{
//生产者处理的资源
private Resource res;
ProducerThread(Resource res){
this.res = res;
}
public void run(){
try{
while(true){
res.set("商品");
}
}
catch(Exception e){
}
}
}
//消费者线程
class ConsumerThread implements Runnable{
//消费者消费的资源
private Resource res;
ConsumerThread(Resource res){
this.res = res;
}
public void run(){
try{
while(true){
res.out();
}
}
catch(Exception e){
}
}
}
class ProCon{
public static void main(String[] args){
//创建共享资源
Resource res = new Resource("商品");
//创建生产者和消费者线程
ProducerThread p1 = new ProducerThread(res);
ProducerThread p2 = new ProducerThread(res);
ConsumerThread c1 = new ConsumerThread(res);
ConsumerThread c2 = new ConsumerThread(res);
//开启线程并进行生产和消费的交替过程
new Thread(p1).start();
new Thread(p2).start();
new Thread(c1).start();
new Thread(c2).start();
}
}