Java 锁定条件等待并通知:IllegalMonitorStateException
Java Lock Condition Wait and Notify: IllegalMonitorStateException
我是 Java 的新手。我刚读完 "core java" 这本书。我遇到了一个关于 'Condition & Lock'.
的问题
我把书上的一段代码敲到eclipse上练习了一下
当我 运行 代码时,"sufficientFund.wait();" 行抛出 IllegalMonitorStateException。为什么这里有例外?
我搜索了一会儿,我知道 "This method should only be called by a thread that is the owner of this object's monitor." 我认为当前线程有锁,因为 'bankLock.lock();' 是在 wait() 之前执行的。
我认为代码的正确行为是,当前线程应该挂在 sufficientFund.wait() 处,但它没有。
package com.first.java;
import java.util.Scanner;
import java.util.concurrent.locks.*;
public class BankTranf {
private static final int NACCOUNT = 3;
public static final double INITAL_BALANCE = 1000;
public static void main(String[] args) {
Bank bank = new Bank(NACCOUNT, INITAL_BALANCE);
for (int i = 0; i < NACCOUNT; i++) {
TransferRunnable transferRunnable = new TransferRunnable(bank, i, INITAL_BALANCE);
Thread thread = new Thread(transferRunnable);
thread.start();
}
System.out.println("press any key to exit.");
Scanner in = new Scanner(System.in);
in.nextLine();
System.exit(0);
}
}
class Bank {
private final double[] account;
private Lock bankLock;
private Condition sufficientFund;
public Bank(int n, double initialBanlance) {
account = new double[n];
for (int i = 0; i < account.length; i++) {
account[i] = initialBanlance;
}
bankLock = new ReentrantLock();
sufficientFund = bankLock.newCondition();
}
public void transfer(int from, int to, double amount) {
bankLock.lock();
try {
while (account[from] < amount) {
System.out.println(Thread.currentThread().getName() + " does'nt hava enough money");
sufficientFund.wait();
}
System.out.println(Thread.currentThread());
account[from] -= amount;
System.out.printf("%10.2f from %d to %d ", amount, from, to);
account[to] += amount;
System.out.printf(" Total balance: %10.2f%n", getTotalBalance());
sufficientFund.signalAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
bankLock.unlock();
}
}
public double getTotalBalance() {
double d = 0;
bankLock.lock();
try {
for (double n : account) {
d += n;
}
return d;
} finally {
bankLock.unlock();
}
}
public int size() {
return account.length;
}
}
class TransferRunnable implements Runnable {
private Bank bank;
private int fromAccount;
private double maxAmount;
private int DELAY = 10;
public TransferRunnable(Bank b, int from, double max) {
bank = b;
this.fromAccount = from;
this.maxAmount = max;
}
@Override
public void run() {
try {
while (true) {
int toAcount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAcount, amount);
Thread.sleep(4000/* (int)(DELAY*Math.random()) */);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
我也尝试了另一种方法,我删除了所有的 Lock 和 Condition,而不是使用 "synchronized",代码如我所料 运行ning。
public synchronized void transfer(int from, int to, double amount) {
//bankLock.lock();
try {
while (account[from] < amount) {
System.out.println(Thread.currentThread().getName() + " does'nt hava enough money");
wait();
}
System.out.println(Thread.currentThread());
account[from] -= amount;
System.out.printf("%10.2f from %d to %d ", amount, from, to);
account[to] += amount;
System.out.printf(" Total balance: %10.2f%n", getTotalBalance());
notifyAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
}
}
public synchronized double getTotalBalance() {
double d = 0;
try {
for (double n : account) {
d += n;
}
return d;
} finally {
}
}
请注意,Condition
因为 Java 中的任何 class 扩展了 Object
,因此它具有继承自 Object
的 wait
方法,我相信你在这里错误地调用了,你打算调用等待条件的方法是 Condition#await
而不是 wait
.
我是 Java 的新手。我刚读完 "core java" 这本书。我遇到了一个关于 'Condition & Lock'.
的问题我把书上的一段代码敲到eclipse上练习了一下
当我 运行 代码时,"sufficientFund.wait();" 行抛出 IllegalMonitorStateException。为什么这里有例外?
我搜索了一会儿,我知道 "This method should only be called by a thread that is the owner of this object's monitor." 我认为当前线程有锁,因为 'bankLock.lock();' 是在 wait() 之前执行的。 我认为代码的正确行为是,当前线程应该挂在 sufficientFund.wait() 处,但它没有。
package com.first.java;
import java.util.Scanner;
import java.util.concurrent.locks.*;
public class BankTranf {
private static final int NACCOUNT = 3;
public static final double INITAL_BALANCE = 1000;
public static void main(String[] args) {
Bank bank = new Bank(NACCOUNT, INITAL_BALANCE);
for (int i = 0; i < NACCOUNT; i++) {
TransferRunnable transferRunnable = new TransferRunnable(bank, i, INITAL_BALANCE);
Thread thread = new Thread(transferRunnable);
thread.start();
}
System.out.println("press any key to exit.");
Scanner in = new Scanner(System.in);
in.nextLine();
System.exit(0);
}
}
class Bank {
private final double[] account;
private Lock bankLock;
private Condition sufficientFund;
public Bank(int n, double initialBanlance) {
account = new double[n];
for (int i = 0; i < account.length; i++) {
account[i] = initialBanlance;
}
bankLock = new ReentrantLock();
sufficientFund = bankLock.newCondition();
}
public void transfer(int from, int to, double amount) {
bankLock.lock();
try {
while (account[from] < amount) {
System.out.println(Thread.currentThread().getName() + " does'nt hava enough money");
sufficientFund.wait();
}
System.out.println(Thread.currentThread());
account[from] -= amount;
System.out.printf("%10.2f from %d to %d ", amount, from, to);
account[to] += amount;
System.out.printf(" Total balance: %10.2f%n", getTotalBalance());
sufficientFund.signalAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
bankLock.unlock();
}
}
public double getTotalBalance() {
double d = 0;
bankLock.lock();
try {
for (double n : account) {
d += n;
}
return d;
} finally {
bankLock.unlock();
}
}
public int size() {
return account.length;
}
}
class TransferRunnable implements Runnable {
private Bank bank;
private int fromAccount;
private double maxAmount;
private int DELAY = 10;
public TransferRunnable(Bank b, int from, double max) {
bank = b;
this.fromAccount = from;
this.maxAmount = max;
}
@Override
public void run() {
try {
while (true) {
int toAcount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAcount, amount);
Thread.sleep(4000/* (int)(DELAY*Math.random()) */);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
我也尝试了另一种方法,我删除了所有的 Lock 和 Condition,而不是使用 "synchronized",代码如我所料 运行ning。
public synchronized void transfer(int from, int to, double amount) {
//bankLock.lock();
try {
while (account[from] < amount) {
System.out.println(Thread.currentThread().getName() + " does'nt hava enough money");
wait();
}
System.out.println(Thread.currentThread());
account[from] -= amount;
System.out.printf("%10.2f from %d to %d ", amount, from, to);
account[to] += amount;
System.out.printf(" Total balance: %10.2f%n", getTotalBalance());
notifyAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
}
}
public synchronized double getTotalBalance() {
double d = 0;
try {
for (double n : account) {
d += n;
}
return d;
} finally {
}
}
请注意,Condition
因为 Java 中的任何 class 扩展了 Object
,因此它具有继承自 Object
的 wait
方法,我相信你在这里错误地调用了,你打算调用等待条件的方法是 Condition#await
而不是 wait
.