练手多线程的交替打印数据的时候出现了一个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异常