多生产者、多消费者问题及java新特性(Lock锁、Condition接口)

生产者、消费者
class Resource
{
private String name;
private int count=1;//编号
private Boolean flag=false;
public synchronized void set(String name)
{
if(flag)
{
try{
this.wait();
}
catch(InterruptedException){

}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
this.flag=true;
this.notify();
}

public synchronized void out()
{
if(!flag)
{
try{
this.wait(); //使当前线程释放cpu的执行权和执行资格,在this锁的线程池中处于冻结状态
}
catch(InterruptedException){

}
}
System.out.println(Thread.currentThread().getName()+”…消费者…”+this.name);
this.flag=false;
this.notify();//唤醒this锁的线程池中任意一个处于冻结状态的线程

}
}

class Producer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.set(“烤鸭”);
}
}
}

class Consumer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.out();
}

}
}

class ProducerConsumerDemo
{
public static void main(String [ ] args)
{
Resource r=new Resource();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
t1.start();
t2.start();
}
}

多生产者多消费者问题:

class Resource
{
private String name;
private int count=1;//编号
private Boolean flag=false;
public synchronized void set(String name)
{
while(flag)
{
try{
this.wait();
}
catch(InterruptedException){

}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
this.flag=true;
this.notifyAll();
}

public synchronized void out()
{
while(!flag)
{
try{
this.wait();
}
catch(InterruptedException){

}
}
System.out.println(Thread.currentThread().getName()+”…消费者…”+this.name);
this.flag=false;
this.notifyAll();

}
}

class Producer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.set(“烤鸭”);
}
}
}

class Consumer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.out();
}

}
}

class ProducerConsumerDemo
{
public static void main(String [ ] args)
{
Resource r=new Resource();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
t1.start();
t2.start();
}
}

程序中为何使用while循环,以及为何使用notifyAll()?
答:if判断的话,只有一次,会导致不该运行的线程运行,例如生产的新数据还没被消费,另一生产者又操作覆盖这样数据,出现了数据错误的情况。
notify()只能唤醒一个线程,如果本方唤醒本方,没有意义,可能导致死锁。
while判断标记解决了线程获取执行权后,是否要运行操作共享数据(新数据还未输出则不操作共享数据)!
notifyAll()解决了本方线程一定会唤醒对方线程,避免了死锁!

notifyAll()唤醒了同一个锁的线程池中的所有冻结线程,效率低。
JDK1.5新特性
同步代码块或同步函数中,对于锁的操作是隐式的。而java1.5以后在java.util.concurrent.locks中提供了Lock接口,将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。其提供了更加强大的功能。
Lock接口有多个实现:如ReentrantLock互斥锁等。
同步代码块示例:
Object obj=new Object();
Void show()
{
synchronized(obj)//对锁的操作隐私
{
code…
}
}

新特性示例:
Lock lock=new ReentrantLock();
Void show()
{
lock.lock();//获取锁
try
{
code…//同步代码块
Throw Exception;
}
finally
{
lock.unlock();//释放锁
}
}

Java.util.concurrent.locks中定义了一个Condition接口,将Object类中的监视方法wait()、notify()、notifyAll()分解成了截然不同的对象,以便通过这些对象与任意Lock实现组合使用,为每个对象提供多个set(wait-set)。其中Lock替代了synchronized方法和同步代码块的使用,Condition替代了Object监视器方法的使用。
传统同步中,一个锁是一个Oject类,该锁对应一组监视方法wait()、notify()、notifyAll()。一段同步代码中,挂一个锁,只能使用该锁对应的一组监视方法wait()、notify()、notifyAll()等,即一个锁上只能有一组监视器,这组监视器即监视着生产者又监视着消费者。
Java1.5中,可以把监视器方法封装成Condition对象,一个Condition对象中有一组监视方法。同一把锁上可以有多个Condition对象。
在Lock类中定义了一个newCondition()方法,获得一个Condition的实例对象,该实例对象内封装了一组监视方法。
Eg:
Lock lock =new ReentrantLock();
Condition c1=lock.newCondition();
Condition c2=lock.newCondition();

示例:
class Resource
{
private String name;
private int count=1;//编号
private Boolean flag=false;
//创建锁对象
Lock lock=new ReentrantLock();
//创建锁上的监视对象
Condition con=lock.newCondition();
public void set(String name)
{
lock.lock();
try
{
while(flag)
{
try{
con.await();
}
catch(InterruptedException){

}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
this.flag=true;
con.signalAll();
}
finally
{
lock.unlock();
}

}

public void out()
{
lock.lock();
try
{
while(!flag)
{
try{
con.await();
}
catch(InterruptedException){
}
}
System.out.println(Thread.currentThread().getName()+”…消费者…”+this.name);
this.flag=false;
con.signalAll();
}
finally{
lock.unlock();
}
}
}

class Producer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.set(“烤鸭”);
}
}
}

class Consumer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.out();
}

}
}

class ProducerConsumerDemo
{
public static void main(String [ ] args)
{
Resource r=new Resource();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
t1.start();
t2.start();
}
}
上述实现仍然是唤醒锁lock的线程池中的所有冻结状态的线程。
Lock中,一个锁上可以挂多个监视器,一个监视生产者,一个监视消费者,但是都属于同一个锁。

class Resource
{
private String name;
private int count=1;//编号
private Boolean flag=false;
//创建锁对象
Lock lock=new ReentrantLock();
//通过已有锁获取两组监视器,一组监视生产者,一组监视消费者。使用同一个锁
Condition producer_con=lock.newCondition();
Condition consumer_con=lock.newCondition();

public void set(String name)
{
lock.lock();
try
{
while(flag)
{
try{
producer_con.await();//使生产者线程冻结
}
catch(InterruptedException){

}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
this.flag=true;
consumer_con.signal();//唤醒消费者线程中的一个冻结线程
}
finally
{
lock.unlock();
}

}

public void out()
{
lock.lock();
try
{
while(!flag)
{
try{
consumer_con.await();//使消费者线程冻结
}
catch(InterruptedException){
}
}
System.out.println(Thread.currentThread().getName()+”…消费者…”+this.name);
this.flag=false;
producer_con.signal();//唤醒生产者线程中的一个冻结线程
}
finally{
lock.unlock();
}
}
}

class Producer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.set(“烤鸭”);
}
}
}

class Consumer implement Runnable
{
private Resource r;
Producer(Resource r)
{
this.r=r;
}
public void run()
{
for(int i=0;i<100;i++)
{
r.out();
}

}
}

class ProducerConsumerDemo
{
public static void main(String [ ] args)
{
Resource r=new Resource();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
t1.start();
t2.start();
}
}
上述程序中,只会唤醒对方线程的一个冻结线程,避免了死锁,以及唤醒所有冻结线程造成的效率低的问题。

总结:
Lock接口:其出现替代了同步代码块或者同步函数,将同步的隐式的操作锁变成了显示的锁操作,且更加灵活,一个锁上可以加上多组监视器。
有多个实现,如ReetrantLock互斥锁
Lock lock=new ReetrantLock();
lock.lock();//获取锁
lock.unlock();//释放锁,通常需要定义在finally代码块中,以免在同步执行的代码中抛出异常,使得线程终止,而锁未释放,其他线程无法获得锁则无法执行。
Condition接口:其出现替代了Object类中的wait、notify、notifyAll方法。
将这些监视器方法单独进行了封装,变成Condition监视器对象,一个Condition监视器对象封装了一组监视方法:await、signal、signalAll等(对应于Object类中的wait、notify、notifyAll)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值