Java中多线程关于wait()和notify()方法的小错误备忘录

来源:互联网 发布:哈尔滨资海网络怎么样 编辑:程序博客网 时间:2024/06/06 03:54

最近在学习Java多线程中,遇到了一个问题,代码如下:

class Obj {//交替打印张三与李四的文字    public static int flag = 0;    public String name;    Obj(String name) {this.name = name;    }    public synchronized void print() {System.out.print(name + "::");System.out.println("打印一段文字");    }}
public class ExceptionInWait {    public static void main(String[] args) {Obj o1 = new Obj("张三");Obj o2 = new Obj("李四");Thread t1 = new Thread() {@Overridepublic void run() {int flag = 1;while (true) {if (flag == Obj.flag) {o1.print();<span style="white-space:pre"></span>Obj.flag = 0;<span style="white-space:pre"></span>o1.notifyAll(); // 错误1<span style="white-space:pre"></span>    } else {<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>    o1.wait(); // 错误2<span style="white-space:pre"></span>} catch (InterruptedException e) {<span style="white-space:pre"></span>    e.printStackTrace();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>    }<span style="white-space:pre"></span>}<span style="white-space:pre"></span>    }<span style="white-space:pre"></span>};<span style="white-space:pre"></span>Thread t2 = new Thread() {<span style="white-space:pre"></span>    @Override<span style="white-space:pre"></span>    public void run() {<span style="white-space:pre"></span>int flag = 0;<span style="white-space:pre"></span>while (true) {<span style="white-space:pre"></span>    if (flag == Obj.flag) {<span style="white-space:pre"></span>o2.print();<span style="white-space:pre"></span>Obj.flag = 1;<span style="white-space:pre"></span>o1.notifyAll(); // 错误3<span style="white-space:pre"></span>    } else {<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>    o2.wait();// 错误4<span style="white-space:pre"></span>} catch (InterruptedException e) {<span style="white-space:pre"></span>    e.printStackTrace();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>    }<span style="white-space:pre"></span>}<span style="white-space:pre"></span>    }<span style="white-space:pre"></span>};<span style="white-space:pre"></span>t1.start();<span style="white-space:pre"></span>t2.start();    }}

出现错误的地方我标明了,作为一个java新手,之前很不理解为什么会导致这样的错误。在仔细阅读了Oracle官方教程中的Concurrency这一章之后,才有所领悟

When a thread invokes d.wait, it must own the intrinsic lock for d

然而在对象中,因为print方法持有synchronized关键字,于是执行完后,已经都把各自的锁给释放掉了

使用wait和notify方法之前,一定要确认当前线程持有的锁对象,如果锁对象不存在,就会发生IllegalMonitorStateException;如果锁对象存在,但是没有像预期一样设置好,程序的运行结果会与预期不同

原文链接:http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html


第一次用编辑器,懒得去纠正错误代码的格式了,下面贴上正确的代码

public class ExceptionInWait {    public static void main(String[] args) {Obj o1 = new Obj("张三", 0);Obj o2 = new Obj("李四", 1);final Object lock = new Object();o1.setLock(lock);o2.setLock(lock);Thread t1 = new Thread() {    @Override    public void run() {while (true) {    o1.print();}    }};t1.setName("张三的线程");Thread t2 = new Thread() {    @Override    public void run() {while (true) {    o2.print();}    }};t2.setName("李四的线程");t1.start();t2.start();    }}class Obj {    public static int flag = 0;    public int targetFlag;    public String name;    private Object lock;    public void setLock(Object lock) {this.lock = lock;    }    Obj(String name, int targetFlag) {this.name = name;this.targetFlag = targetFlag;    }    public void print() {synchronized (lock) {    if (targetFlag == flag) {System.out.print(name + "::");System.out.println("打印一段文字");//Alter the conditionif(Obj.flag==1){    Obj.flag=0;}else{    Obj.flag=1;}lock.notifyAll();//线程通讯一定要使用正确的锁对象;wait和notify方法的前提是该线程持有锁对象!    }else{try {    lock.wait();} catch (InterruptedException e) {    e.printStackTrace();}    }}    }}


0 0
原创粉丝点击