Java提供了一套API来支持线程之间的交互。在Object类中提供了一套等待通知的API
wait()
notify()
notifyAll()
此处要注意的是,绝不要在循环外面调用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
原文地址:http://blog.51cto.com/12222886/2060728
时间: 2024-10-13 11:30:50