java.lang.IllegalMonitorStateException异常

本文探讨了在多线程环境下,使用synchronized关键字结合wait和notify方法时遇到的IllegalMonitorStateException异常。通过具体案例分析,解释了异常产生的原因,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

练手多线程的交替打印数据的时候出现了一个illegalMonitorStateException异常!先说练习的内容吧!
内容:模仿银行取钱操作,假设一个账户有两个用户在同时取钱,甲用户每次取200元,乙用户每次取300元,要求:实现多线程的访问并让甲乙交替取钱。

先贴出有异常的代码:

	@Override
	public void run() {
		while(true) {
			synchronized (account) {			
			if (drawAccount <= account.getBalance()) { //同步代码块中使用wait方法和notify方法必须保证wait的对象和锁一致
				notify();
				System.out.println(Thread.currentThread().getName() + "取走" + drawAccount + "元");
				account.setBalance(account.getBalance() - drawAccount);
				System.out.println("账户还剩" + account.getBalance());
				try {
					wait();  //利用wait方法和notify方法实现线程通信,甲乙两个用户交替取钱的情况
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}else {
				System.out.println(Thread.currentThread().getName()+"取钱失败");
				break;
				}
			}
		}
	}

在没有线程通信之前(无添加wait和notify方法),代码顺利运行。但是添加了后,运行出现异常,显示illegalMonitorExceptiony,查了很多方法,最后大概明白了在同步代码块中使用wait方法和notify方法,其调用对象是需要和同步代码块的锁一致(我的通俗理解,大神勿喷)。

网上大神说下面三种情况会出现这样的异常(附上出处以下三种情况出处):
1当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;
2当前线程不含有当前对象的锁资源的时候,调用obj.notify()方法。
3当前线程不含有当前对象的锁资源的时候,调用obj.notifyAll()方法

还有大概就是在非同步方法中或同步代码块中使用这两个方法。

完整正确代码:

package threadExercise1;

class Account {
	private String accountNo;
	private int balance;
	
	public Account(String accountNo, int balance) {
		this.accountNo = accountNo;
		this.balance = balance;
	}
	
	public String getAccountNo() {
		return accountNo;
	}

	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}

	public int getBalance() {
		return balance;
	}
	public void setBalance(int balance) {
		this.balance = balance;
	}
	//利用账户号来重写hashcode方法和equals方法
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((accountNo == null) ? 0 : accountNo.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Account other = (Account) obj;
		if (accountNo == null) {
			if (other.accountNo != null)
				return false;
		} else if (!accountNo.equals(other.accountNo))
			return false;
		return true;
	}

	
	
}

class DrawAccount implements Runnable{
	private Account account;
	private int drawAccount;

	public DrawAccount(Account account, int drawAccount) {
		super();
		this.account = account;
		this.drawAccount = drawAccount;
	}

	@Override
	public void run() {
		while(true) {
			synchronized (account) {			
			if (drawAccount <= account.getBalance()) { //同步代码块中使用wait方法和notify方法必须保证wait的对象和锁一致
				account.notify();
				System.out.println(Thread.currentThread().getName() + "取走" + drawAccount + "元");
				account.setBalance(account.getBalance() - drawAccount);
				System.out.println("账户还剩" + account.getBalance());
				try {
					account.wait();  //利用wait方法和notify方法实现线程通信,甲乙两个用户交替取钱的情况
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}else {
				System.out.println(Thread.currentThread().getName()+"取钱失败");
				break;
				}
			}
		}
	}
}

public class TestBank {
	public static void main(String[] args) {
		Account account = new Account("888",6000);
		DrawAccount da1 = new DrawAccount(account,200);
		DrawAccount da2 = new DrawAccount(account,300);
//		da1.start();
//		da2.start();
		
		Thread t1 = new Thread(da1);
		Thread t2 = new Thread(da2);
		
		t1.setName("甲");
		t2.setName("乙");
		t1.start();
		t2.start();
		
	}
}

最后附上觉得很有参考价值的文章:诡异的illegalMonitorException异常

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值