Ожидание и уведомление о состоянии блокировки Java: IllegalMonitorStateException

Я новичок в Java. Я только что прочитал книгу "core java". Я столкнулся с проблемой "Состояние и замок".

Я набрал кусок кода из книги до затмения, чтобы немного попрактиковаться.

Когда я запускаю код, строка "достаточное количество Fund.wait();" генерирует исключение IllegalMonitorStateException. Почему здесь есть исключение?

Я некоторое время гуглил, знаю, что "Этот метод должен вызываться только потоком, который является владельцем монитора этого объекта". Я думаю, что текущий поток имеет блокировку, потому что 'bankLock.lock();' выполняется непосредственно перед wait(). Я думаю, что правильное поведение кода заключается в том, что текущий поток должен быть подвешен в достаточном количестве Fund.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();
        }
    }
}

Я также попробовал другой способ, я удаляю все блокировки и условия, вместо того, чтобы использовать "синхронизированный", код работал так, как я ожидал.

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 {

        }
    }

1 ответ

Решение

Обратите внимание, что Condition как любой класс в Java расширяется Object и, следовательно, он имеет wait метод, унаследованный от ObjectЯ полагаю, что вы вызываете по ошибке здесь, метод, который вы должны вызывать для ожидания условия Condition#await скорее, чем wait,

Другие вопросы по тегам