2016-05-29 2 views
1

Я новичок в Java. Я просто прочитал книгу «core java». Я встретил проблему «Условие & Lock».Состояние блокировки Java Ожидание и уведомление: IllegalMonitorStateException

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

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

Я hava googled какое-то время, я знаю, что «этот метод должен быть вызван потоком, который является владельцем монитора этого объекта». Я думаю, что текущий поток имеет замок, потому что «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 { 

     } 
    } 

ответ

2

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

+0

Да, вы правы! – gfan

Смежные вопросы