这次是生产者消费者的问题,将线程增加到了4个,这样原来用 if 条件判断是否 wait() 线程,在这个实例中就会有一些小问题了(会导致多生产而没有消费)。而且只用 notify() 唤醒等待线程有可能还会造成死锁。
因此需要改进代码:
package thread;
public class ProducerConsumerDemo {
public static void main(String[] args) {
//创建资源对象
Resource res = new Resource();
Producer p1 = new Producer(res);
Consumer c1 = new Consumer(res);
//创建线程
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
//开启4个线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//共有资源类
class Resource{
String name = null;
int i=0;
//是否生产的标志
boolean flag = false;
}
class Producer implements Runnable{
Resource res = new Resource();
Producer(Resource res){
this.res = res;
}
public void run(){
//用循环判断标志位可以防止多生产或者多消费
while(true){
//判断如果生产过了就等待消费
if(res.flag){
try{
res.wait();
}catch(Exception e){
}
}
//同步锁防止同时多生产
synchronized(res){
res.name = Thread.currentThread().getName()+"..."+res.i++;
System.out.println(res.name+"...生产");
//改变标志位表示已生产
res.flag = true;
//唤醒所有等待线程,主要目的是唤醒消费线程,但是不可避免唤醒其他生产线程
res.notifyAll();
}
}
}
}
class Consumer implements Runnable{
Resource res = new Resource();
Consumer(Resource res){
this.res = res;
}
public void run(){
//用循环判断标志位可以防止多生产或者多消费
while(true){
//判断如果消费过了就等待生产
if(!res.flag){
try{
res.wait();
}catch(Exception e){
}
}
//同步锁,防止同时多消费
synchronized(res){
System.out.println("销售..."+res.name);
//改变标志位,表示已消费
res.flag = false;
//唤醒所有等待线程,主要目的是唤醒生产线程,但是不可避免唤醒其他消费线程
res.notifyAll();
}
}
}
}
在JDK1.5之后同步锁可以使用ReentrantLock().lock() 来代替,ReentrantLock().unlock() 来解锁。wait() notify() notifyAll() 也用Condition().await() Condition().signal() Condition().signalAll() 来代替,并且可以指定线程进行唤醒或等待操作。
package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProducerConsumerDemo2 {
public static void main(String[] args) {
//创建资源对象
Resource2 r2 = new Resource2();
Producer2 p2 = new Producer2(r2);
Consumer2 c2 = new Consumer2(r2);
//创建线程
Thread t1 = new Thread(p2);
Thread t2 = new Thread(c2);
Thread t3 = new Thread(p2);
Thread t4 = new Thread(p2);
//开启4个线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//资源类
class Resource2 {
private String name;
private int count = 1;
private boolean flag = false;
//创建锁对象
private Lock lock = new ReentrantLock();
// private Condition condition = lock.newCondition();
//为消费者和生产者分别创建condition,有助于分开等待和唤醒
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void produce(String name){
//锁定
lock.lock();
try{
//用循环判断标志位可以防止多生产或者多消费
while(flag){
try {
//生产者线程等待
condition_pro.await();
} catch (InterruptedException e) {
}
}
this.name = name +"..."+count++;
System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);
//改变标志位表示已生产
flag = true;
//唤醒消费者线程
condition_con.signal();
//解锁,这里使用finally是因为无论中间程序执行是否成功,都必须释放锁,否则会死锁
}finally{
lock.unlock();
}
}
public void consume(){
//锁定
lock.lock();
try{
//用循环判断标志位可以防止多生产或者多消费
while(!flag){
try {
//消费者线程等待
condition_con.await();
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName()+"..."+this.name+"...消费");
//改变标志位表示已消费
flag = false;
//唤醒生产者线程
condition_pro.signal();
//解锁,这里使用finally是因为无论中间程序执行是否成功,都必须释放锁,否则会死锁
}finally{
lock.unlock();
}
}
}
//生产者
class Producer2 implements Runnable{
private Resource2 r2 = new Resource2();
Producer2(Resource2 r2){
this.r2 = r2;
}
public void run() {
while(true){
r2.produce("AAA");
}
}
}
//消费者
class Consumer2 implements Runnable{
private Resource2 r2 = new Resource2();
Consumer2(Resource2 r2){
this.r2 = r2;
};
public void run() {
while(true){
r2.consume();
}
}
}