手记

Java线程与并发编程实践----等待通知(生产者消费者问题)线程

    Java提供了一套API来支持线程之间的交互。在Object类中提供了一套等待通知的API

    wait()

    notify()

    notifyAll()

    此处要注意的是,绝不要在循环外面调用wait()方法。原因如下:

    对于从wait中被notify的进程来说,它在被notify之后还需要重新检查是否符合执行条件,如果不符合,就必须再次被wait,

如果符合才能往下执行。所以:wait方法应该使用循环模式来调用。按照上面的生产者和消费者问题来说:错误情况一:如果有两个生

产者A和B,一个消费者C。当存储空间满了之后,生产者A和B都被wait,进入等待唤醒队列。当消费者C取走了一个数据后,如果调用了

notifyAll(),注意,此处是调用notifyAll(),则生产者线程A和B都将被唤醒,如果此时A和B中的wait不在while循环中而是在if

中,则A和B就不会再次判断是否符合执行条件,都将直接执行wait()之后的程序,那么如果A放入了一个数据至存储空间,则此时存储

空间已经满了;但是B还是会继续往存储空间里放数据,错误便产生了。错误情况二:如果有两个生产者A和B,一个消费者C。当存储空

间满了之后,生产者A和B都被wait,进入等待唤醒队列。当消费者C取走了一个数据后,如果调用了notify(),则A和B中的一个将被

唤醒,假设A被唤醒,则A向存储空间放入了一个数据,至此空间就满了。A执行了notify()之后,如果唤醒了B,那么B不会再次判断

是否符合执行条件,将直接执行wait()之后的程序,这样就导致向已经满了数据存储区中再次放入数据。错误产生。


    下面使用消费者与生产者问题来展示以上API的使用:

package xiancheng;public class PC {	public static void main(String[] args) {		Shared s = new Shared();		Thread t1 = new Thread(new Product(s));		Thread t2 = new Thread(new Consumer(s));		t1.start();		t2.start();	}}class Shared {		private char c;	private volatile boolean writeable = true;		public synchronized void setChar(char ch) {		while(!writeable) {			try {				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		this.c = ch;		writeable = false;		notify();	}		public synchronized char getChar() {		while(writeable) {			try {				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		writeable = true;		notify();		return c;	}}class Product implements Runnable{		private Shared s;	public Product(Shared s) {		this.s = s;	}	@Override	public void run() {		for (char i = 'A'; i < 'Z'; i++) {			s.setChar(i);			System.out.println("生产者生产了一个" + i);		}	}	}class Consumer implements Runnable{		private Shared s;	public Consumer(Shared s) {		this.s = s;	}	@Override	public void run() {		char ch;		do {			ch = s.getChar();			System.out.println("消费者消费了一个" + ch);		} while (ch != 'Z');	}}

打印结果:

消费者消费了一个A生产者生产了一个A生产者生产了一个B消费者消费了一个B生产者生产了一个C消费者消费了一个C生产者生产了一个D消费者消费了一个D生产者生产了一个E消费者消费了一个E生产者生产了一个F消费者消费了一个F生产者生产了一个G消费者消费了一个G生产者生产了一个H消费者消费了一个H生产者生产了一个I消费者消费了一个I生产者生产了一个J消费者消费了一个J生产者生产了一个K消费者消费了一个K生产者生产了一个L生产者生产了一个M消费者消费了一个L消费者消费了一个M生产者生产了一个N消费者消费了一个N生产者生产了一个O消费者消费了一个O生产者生产了一个P消费者消费了一个P生产者生产了一个Q消费者消费了一个Q生产者生产了一个R消费者消费了一个R生产者生产了一个S消费者消费了一个S生产者生产了一个T消费者消费了一个T生产者生产了一个U消费者消费了一个U生产者生产了一个V消费者消费了一个V生产者生产了一个W消费者消费了一个W生产者生产了一个X消费者消费了一个X生产者生产了一个Y消费者消费了一个Y

很明显第一二行就出现了问题,消费出现在了生产之前,查看代码就知道,生产与消费的顺序并没有错乱,只是打印顺序不对而已,因为唤醒动作是在打印之前,

改进代码如下:

package xiancheng;public class PC {	public static void main(String[] args) {		Shared s = new Shared();		Thread t1 = new Thread(new Product(s));		Thread t2 = new Thread(new Consumer(s));		t1.start();		t2.start();	}}class Shared {		private char c;	private volatile boolean writeable = true;		public synchronized void setChar(char ch) {		while(!writeable) {			try {				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		this.c = ch;		writeable = false;		notify();	}		public synchronized char getChar() {		while(writeable) {			try {				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		writeable = true;		notify();		return c;	}}class Product implements Runnable{		private final Shared s;	public Product(Shared s) {		this.s = s;	}	@Override	public void run() {		for (char i = 'A'; i < 'Z'; i++) {			synchronized(s) {				s.setChar(i);				System.out.println("生产者生产了一个" + i);			}		}	}	}class Consumer implements Runnable{		private final Shared s;	public Consumer(Shared s) {		this.s = s;	}	@Override	public void run() {		char ch;		do {			synchronized(s) {				ch = s.getChar();				System.out.println("消费者消费了一个" + ch);			}		} while (ch != 'Z');	}}

运行结果:

生产者生产了一个A消费者消费了一个A生产者生产了一个B消费者消费了一个B生产者生产了一个C消费者消费了一个C生产者生产了一个D消费者消费了一个D生产者生产了一个E消费者消费了一个E生产者生产了一个F消费者消费了一个F生产者生产了一个G消费者消费了一个G生产者生产了一个H消费者消费了一个H生产者生产了一个I消费者消费了一个I生产者生产了一个J消费者消费了一个J生产者生产了一个K消费者消费了一个K生产者生产了一个L消费者消费了一个L生产者生产了一个M消费者消费了一个M生产者生产了一个N消费者消费了一个N生产者生产了一个O消费者消费了一个O生产者生产了一个P消费者消费了一个P生产者生产了一个Q消费者消费了一个Q生产者生产了一个R消费者消费了一个R生产者生产了一个S消费者消费了一个S生产者生产了一个T消费者消费了一个T生产者生产了一个U消费者消费了一个U生产者生产了一个V消费者消费了一个V生产者生产了一个W消费者消费了一个W生产者生产了一个X消费者消费了一个X生产者生产了一个Y消费者消费了一个Y


0人推荐
随时随地看视频
慕课网APP