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

最近在学习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() {
@Override
public 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 condition
		if(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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值