встречайте исключение IllegalMonitorStateException при многопоточном программировании на Java

#java #multithreading #wait #synchronized #notify

#java #многопоточность #подождите #синхронизировано #уведомлять

Вопрос:

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

 public class SychronizedBlock {

    static int balance = 0;
    static Integer lock = 0;


    public static void deposit(int amt) {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                acquire_lock();
                int holdings = balance;
                balance = holdings   amt;
                System.out.println("deposit "   amt   ", balance: "   balance);
                release_lock();
            }
        });
        t1.start();

    }

    public static void acquire_lock() {
        synchronized(lock) {
            while (lock == 1) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            lock = 1;
        }
    }

    public static void release_lock() {
        synchronized(lock) {
            lock = 0;
            lock.notifyAll();
        }
    }

    public static void test1() {
        balance = 0;
        deposit(500);
        deposit(500);
    }

    public static void main(String[] args) {
        test1();
    }
}
  

Однако при запуске программы я столкнулся с исключением IllegalMonitorStateException. Я думаю, что я поместил функции wait() и notifyAll() в синхронизированный блок, и я установил блокировку в качестве параметра synchronized . Почему у меня все еще есть исключение?

Ответ №1:

Проблема в вашем release_lock методе. Вы переназначаете lock значение 0 перед вызовом lock.notifyAll(). , что означает, что notifyAll будет вызываться для нового целочисленного объекта, который не заблокирован. Измените код на следующий, чтобы устранить проблему.

 public static void release_lock() {
    synchronized(lock) {            
        lock.notifyAll();
        lock = 0;
    }
}
  

Комментарии:

1. Или лучше, просто избегайте изменения lock переменной. Очень редко — если вообще когда-либо — хорошая идея синхронизировать переменную, которая может измениться. (Я бы также избегал использования Integer блокировок for из-за эффекта кэширования. Обычно я предпочитаю блокировать равнину Object , которая используется только для этой цели.)

2. Получите это! Большое спасибо за ваше четкое объяснение! Я не понимал, что оператор «lock = 0» раньше назначит новый объект для блокировки.