最近在听java的课,老师的PPT上有一个线程同步的例子,是要利用synchronized、wait和notify来实现。我把它输入到电脑并且补全了所有罗杰。运行之后发现它没有按照预想的输出结果。琢磨了好久之后,才找到法门。
代码如下:
一个栈的模拟:
View Code
package ThreadDemo; import java.util.*; public class StackDemo { private Vector buffer = new Vector(400, 200); public synchronized char pop() { char c; while(buffer.size() == 0) { try { this.wait(); } catch(InterruptedException e){} } Object top = buffer.remove(buffer.size() - 1); c = (Character)top; return c; } public synchronized void push(char c) { this.notify(); Character charObj = new Character(c); buffer.addElement(charObj); } }
两个线程:
View Code
package ThreadDemo; public class ThreadPush implements Runnable { StackDemo stack = new StackDemo(); public void run() { char c; for(int i=0; i < 200; i++) { c = (char)(Math.random()*26 + 'A'); stack.push(c); try { Thread.sleep(300); } catch(InterruptedException e){} } } }
和:
View Code
package ThreadDemo; import java.util.*; public class ThreadPop implements Runnable { StackDemo stack = new StackDemo(); public void run() { char c; for(int i = 0; i < 200; i ++) { c = stack.pop(); System.out.println(c); try { Thread.sleep(300); } catch(InterruptedException e){} } } }
主函数:
View Code
package ThreadDemo; public class ThreadDemoMain { public static void main(String[] args) { ThreadPush pushObject = new ThreadPush(); Thread thread1 = new Thread(pushObject); thread1.start(); ThreadPop popObject = new ThreadPop(); Thread thread2 = new Thread(popObject); thread2.start(); } }
执行的情况是:pop线程一旦wait就再也醒不来了;push线程倒是一直在正常工作。这我就很纳闷,push进去那么多,而且notify语句也执行了,pop线程始终跟喝醉了似的,没有任何反应。无奈之下,我把PPT又翻出来,重新看wait的用法。发现它说,x.wait()之后,线程就进入了x对象的等待池。我的程序里边用的是,this.wait,this是谁?不就是StackDemo的实例嘛?。。。哦,我明白了,两个线程使用了两个不相同的StackDemo实例。这。。。
修改之后的代码:
栈模拟的代码没变。。。
两个线程:(在构造函数中要求传入StackDemo的实例,而不是自己生成!!!)
View Code
package ThreadDemo; public class ThreadPush implements Runnable { StackDemo stack = null; public ThreadPush(StackDemo stack) { this.stack = stack; } public ThreadPush(){} public void run() { char c; for(int i=0; i < 200; i++) { c = (char)(Math.random()*26 + 'A'); stack.push(c); try { Thread.sleep(300); } catch(InterruptedException e){} } } }
和:
View Code
package ThreadDemo; import java.util.*; public class ThreadPop implements Runnable { StackDemo stack = null; public ThreadPop(StackDemo stack) { this.stack = stack; } public ThreadPop(){} public void run() { char c; for(int i = 0; i < 200; i ++) { c = stack.pop(); System.out.println(c); try { Thread.sleep(300); } catch(InterruptedException e){} } } }
主函数:(创建一个StackDemo实例,并且传入两个线程!!!)
View Code
package ThreadDemo; public class ThreadDemoMain { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub StackDemo stack = new StackDemo(); ThreadPush pushObject = new ThreadPush(stack); Thread thread1 = new Thread(pushObject); thread1.start(); ThreadPop popObject = new ThreadPop(stack); Thread thread2 = new Thread(popObject); thread2.start(); } }
嗒嗒,程序终于正常工作了,乖乖地push进去200个字符,并且在pop之后输出。
这个故事告诉我们,上锁啊,等待啊,通知啊,都要对相同的对象才行。否则,就会出现我遇到的情况,一个按规定发通知,另一个死等,啥也没等到。