下面的是优化版本
/** 用一个线程输入姓名和性别,用另一个线程输出姓名和性别的 优化版本! @author zck; @version V1.1; */ class Resource{ private String name; private String sex; private boolean flag = false; //用来作为判定输入是否已经输出的标识 public synchronized void setNameSex(String name,String sex){ if (flag){ try{ this.wait(); }catch(InterruptedException e){ } } this.name = name; this.sex = sex; flag = true; notify(); } public synchronized void getNameSex(){ if (!flag){ try{ this.wait(); }catch(InterruptedException e){ } } System.out.println(this.name+"......"+this.sex); flag = false; notify(); } } class Input implements Runnable{ private Resource res; Input(Resource res){ this.res = res; } public void run(){ int x = 0; while(true){ if(x==0){ res.setNameSex("张三","男"); }else { res.setNameSex("WWW","woman"); } x = (x+1)%2; } } } class Output implements Runnable{ private Resource res; Output(Resource res){ this.res = res; } public void run(){ while(true){ res.getNameSex(); } } } class ThreadCommunicationDemo2{ //优化版本 public static void main(String[] args){ Resource r = new Resource(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); } }在屏幕上打印输出时,有时候会出现生产两次却只消费了一次的情况,这与预期的生产一次消费一次不符合,这种安全隐患来自于flag的if判断,因为只判定一次,当生产线程1通过if判断时,执行完wait语句就失去了执行权,然后接下来消费线程1执行,然后生产线程2执行(因为此时flag是false),当生产线程2执行完时,flag变成了true,但是由于生产线程1已经在之前中通过了if判断,当生产线程1获得执行权时,就会再生产一次; 打印结果: 生产商品1 消费商品1 生产商品2 生产商品3 消费商品3 改进方法就是将if换成while判断
还有一种安全隐患就是notify叫醒的线程池里本类线程,就会出现叫醒生产线程1叫醒生产线程2,然后所有线程都挂了(都进入wait状态);处理方式就是改notify为notifyAll,干脆全叫醒,就不会出现所有线程一起挂在那儿的情况了;
class ProducerConsumerDemo{ public static void main(String[] args){ ProducerConsumer pc = new ProducerConsumer(); Producer pro = new Producer(pc); Consumer con = new Consumer(pc); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class ProducerConsumer{ private String name; private int count = 1; private boolean flag = false; public synchronized void setName(String name){ while(true){ while(flag){ try{ wait(); }catch(InterruptedException e){ } } this.name = name+"..."+count++; System.out.println(Thread.currentThread().getName()+"---生产---"+this.name); flag = true; this.notifyAll(); } } public synchronized void getName(){ while(true){ while(!flag){ try{ wait(); }catch(InterruptedException e){ } } System.out.println(Thread.currentThread().getName()+"---消费-----"+this.name); flag = false; this.notifyAll(); } } } class Producer implements Runnable{ ProducerConsumer pc; Producer(ProducerConsumer pc){ this.pc = pc; } public void run(){ pc.setName("商品"); } } class Consumer implements Runnable{ ProducerConsumer pc; Consumer(ProducerConsumer pc){ this.pc = pc; } public void run(){ pc.getName(); } }下面是java5.0改进版本 1. 引入了lock代替synchronized,condition对象的await代替wait,signal和signalAll代替notify和notifyAll;
import java.util.concurrent.locks.*; class ProducerConsumerDemo2{ public static void main(String[] args){ ProducerConsumer pc = new ProducerConsumer(); Producer pro = new Producer(pc); Consumer con = new Consumer(pc); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class ProducerConsumer{ private String name; private int count = 1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void setName(String name) throws InterruptedException{ lock.lock(); try{ while(flag){ condition_pro.await(); } this.name = name+"..."+count++; System.out.println(Thread.currentThread().getName()+"---生产---"+this.name); flag = true; condition_con.signalAll(); }finally{ lock.unlock(); } } public void getName() throws InterruptedException{ lock.lock(); try{ while(!flag){ condition_con.await(); } System.out.println(Thread.currentThread().getName()+"---消费-----"+this.name); flag = false; condition_pro.signalAll(); }finally{ lock.unlock(); } } } class Producer implements Runnable{ ProducerConsumer pc; Producer(ProducerConsumer pc){ this.pc = pc; } public void run(){ while(true){ try{ pc.setName("商品"); }catch(InterruptedException e){ } } } } class Consumer implements Runnable{ ProducerConsumer pc; Consumer(ProducerConsumer pc){ this.pc = pc; } public void run(){ while(true){ try{ pc.getName(); }catch(InterruptedException e){ } } } }