下面参照《Java就业培训教材》写了一个相似的线程之间通信的例子,程序实现了一个生产者和一个消费者,还有一个buffer用于存放生产出来的一个对象,buffer中只可以存放一个对象,buffer有一个标志位bFull,如果标志位为true表示buffer里有数值,如果bFull为false表示没有数值。buffer中的对象有两个属性,在多线程中如果不处理同步的话,可能出现属性不对应的情况。
wait:告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify为止。
notify:唤醒同一对象监视器中调用wait的第一线程。用于类似饭馆有一个空位子后通知所有等候就餐的顾客中的第一位可以入座的情况。
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况。
从上面明显可以看出wait、notify和notifyAll只能在synchronized方法中调用,记住一个对象的notify只能够唤醒被同一个对象wait的线程。
class ThreadDemo { public static void main(String[] args) { Buffer buf = new Buffer(); new Producer(buf).start(); new Consumer(buf).start(); } } class Producer extends Thread { private Buffer buf; public Producer(Buffer buf) { this.buf = buf; } public void run() { boolean odd = false; while(true) { if(odd) { buf.name="jack"; try{Thread.sleep(1000);}catch(Exception e) {} buf.sex="female"; } else { buf.name="lucy"; try{Thread.sleep(1000);}catch(Exception e) {} buf.sex="male"; } odd = !odd; } } } class Consumer extends Thread { private Buffer buf; public Consumer(Buffer buf) { this.buf = buf; } public void run() { while(true) { try{Thread.sleep(1000);}catch(Exception e) {} System.out.println(buf.name + " : " + buf.sex); } } } class Buffer { boolean bFull; String name = "Unkown"; String sex = "Unkown"; }
结果 写道
线程不同步回去出现jack : male,lucy : female 这些错误的输出。
class ThreadDemo { public static void main(String[] args) { Buffer buf = new Buffer(); new Producer(buf).start(); new Consumer(buf).start(); } } class Producer extends Thread { private Buffer buf; public Producer(Buffer buf) { this.buf = buf; } public void run() { boolean odd = false; while(true) { synchronized(buf) { if(odd) { buf.name="jack"; try{Thread.sleep(100);}catch(Exception e) {} buf.sex="female"; } else { buf.name="lucy"; try{Thread.sleep(100);}catch(Exception e) {} buf.sex="male"; } } odd = !odd; } } } class Consumer extends Thread { private Buffer buf; public Consumer(Buffer buf) { this.buf = buf; } public void run() { while(true) { synchronized(buf) { try{Thread.sleep(100);}catch(Exception e) {} System.out.println(buf.name + " : " + buf.sex); } } } } class Buffer { boolean bFull; String name = "Unkown"; String sex = "Unkown"; }
没有采用线程通信会出现Unkown : Unkown 和连续输出lucy和jack的情况。
class ThreadDemo { public static void main(String[] args) { Buffer buf = new Buffer(); new Producer(buf).start(); new Consumer(buf).start(); } } class Producer extends Thread { private Buffer buf; public Producer(Buffer buf) { this.buf = buf; } public void run() { boolean odd = false; while(true) { synchronized(buf) { if(buf.bFull) try{buf.wait();}catch(Exception e) {} if(odd) { buf.name="jack"; try{Thread.sleep(100);}catch(Exception e) {} buf.sex="female"; } else { buf.name="lucy"; try{Thread.sleep(100);}catch(Exception e) {} buf.sex="male"; } buf.bFull = true; buf.notify(); } odd = !odd; } } } class Consumer extends Thread { private Buffer buf; public Consumer(Buffer buf) { this.buf = buf; } public void run() { while(true) { synchronized(buf) { if(!buf.bFull) try{buf.wait();}catch(Exception e) {} //try{Thread.sleep(100);}catch(Exception e) {} System.out.println(buf.name + " : " + buf.sex); buf.bFull = false; buf.notify(); } } } } class Buffer { boolean bFull = false; String name = "Unkown"; String sex = "Unkown"; }
结果达到了预期的目的。
class ThreadDemo { public static void main(String[] args) { Buffer buf = new Buffer(); new Producer(buf).start(); new Consumer(buf).start(); } } class Producer extends Thread { private Buffer buf; public Producer(Buffer buf) { this.buf = buf; } public void run() { boolean odd = false; while(true) { if(odd) { buf.put("jack","female"); } else { buf.put("lucy","male"); } odd = !odd; } } } class Consumer extends Thread { private Buffer buf; public Consumer(Buffer buf) { this.buf = buf; } public void run() { while(true) { buf.get(); } } } class Buffer { private boolean bFull = false; private String name = "Unkown"; private String sex = "Unkown"; public synchronized void put(String name, String sex) { if(bFull) try{wait();}catch(Exception e) {} this.name = name; this.sex = sex; bFull = true; notify(); } public synchronized void get() { if(!bFull) try{wait();}catch(Exception e) {} System.out.println(name + " : " + sex); bFull = false; notify(); } }