2013-03-27 2 views
0

У меня есть программа, которая имитирует ворота на корабль. Они работают в потоках. Идея состоит в том, чтобы позволить им запускать и приостанавливать во время случайного момента в методе run для имитации прохождения людей. Это делается всеми потоками, между тем главный поток ждет уведомления и проверяет, заполняется ли корабль, когда сообщено потоками, что они добавили человека, проходящего через ворота, основной поток снова проверяет, если судно заполнено. Программа имеет три класса:IllegalMonitorStateException при уведомлении нитей

Счетчик:

public class Counter { 
     private int currentValue[]; 
     private int maxValue; 

     public Counter(int[] nrOfPeople, int max) { 
      currentValue = nrOfPeople; 
      currentValue[0] = 0; 
      maxValue = max; 
     } 

     public synchronized void addPersons(int nr_p) { 
      currentValue[0] += nr_p; 
     } 

     public synchronized int getValue() { 
      return currentValue[0]; 
     } 

     public synchronized boolean isFull() { 
      if(currentValue[0] < maxValue) 
       return false; 
      return true; 
     } 
    } 

ворота Класс:

public abstract class Gate implements Runnable { 
     int nrOfPassengers; 
     int gatenr; 
     int gatesize; 
     Counter c; 
     private Thread t; 
     private Random r; 
     private boolean blocked; /* suspends people from passing */ 

     public Gate(Counter c, int nr) { 
      this.c = c; 
      gatenr = nr; 
      this.open(); 
      r = new Random(); 
      t = new Thread(this); 
      t.start(); 
     } 

     public void setGatesize(int size) { 
      gatesize = size; 
     } 

     public void close() { 
      blocked = true; 
     } 

     public void open() { 
      blocked = false; 
     } 

     public int getNoOfPassangers() { 
      return nrOfPassengers; 
     } 

     public int getId() { 
      return gatenr; 
     } 

     @Override 
     public void run() { 
      while(!blocked) { 
       int waitTime = (r.nextInt(5) + 1) * 1000; /* between 1-5 seconds */ 
       System.out.println("Person-Gate " + gatenr + ": adding one to " + c.getValue()); 
       try { 
        /* bigger throughput => amount can vary */ 
        if(gatesize > 1) { 
         int persons = r.nextInt(gatesize)+1; 
         c.addPersons(persons); 
         nrOfPassengers += persons; 
        } else { 
         c.addPersons(1); 
         nrOfPassengers++; 
        } 
        Thread.sleep(waitTime); 
       } catch (InterruptedException e) { 
        System.out.println("Person-Gate " + gatenr + ": was interrupted adding person"); 
        e.printStackTrace(); 
       } 
       System.out.println("Person-Gate " + gatenr + ": added one to " + c.getValue()); 
       t.notify(); 
      } 
     } 

     public void join() { 
      try { 
       t.join(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

И Simulator, который запускает основной метод:

/* 
    * This class simulates cars and persons- entering a ferry. 
    */ 
    public class Simulator { 

     public static final int MAX = 30; 

     public static void main(String[] args) { 
      int nrOfPeople[] = new int[1]; /* array of size one for keeping count */ 
      ArrayList<Gate> gates = new ArrayList<Gate>(); 
      Counter counter = new Counter(nrOfPeople, MAX); 
      Thread mainThread = Thread.currentThread(); 

      /* adding 3 person-gates */ 
      for(int i=1; i<4; i++) { 
       gates.add(new PersonGate(counter, i)); 
      } 

      /* let all gates work as long as passengers is under MAX */ 
      while(!counter.isFull()) { 
       try { 
        mainThread.wait(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
      System.out.println("Announcement: Ship is full!"); 

      /* wait for child threads to finish */ 
      for(Gate g: gates) { 
       g.close(); 
       try { 
        g.join(); 
       } catch (Exception e) { /* InterruptedException */ 
        e.printStackTrace(); 
       } 
       System.out.println(g.getNoOfPassangers() + " passed through gate nr " + g.getId()); 
       System.out.println(counter.getValue() + " has passed in total"); 
      } 

     } 
    } 

Im получение погрешность

Person-Gate 1: adding one to 0 
Person-Gate 2: adding one to 1 
Person-Gate 3: adding one to 2 
Exception in thread "main" java.lang.IllegalMonitorStateException 
at java.lang.Object.wait(Native Method) 
at java.lang.Object.wait(Object.java:485) 
at Simulator.main(Simulator.java:24) 
Person-Gate 3: added one to 3Exception in thread "Thread-3" 

Кто-нибудь теперь что-то происходит?

ответ

0

Вы должны владеть монитором объекта, на который вы вызываете wait или notify. Значение, вы должны быть в synchonize-Block, как

synchronized(objectUsedAsSynchronizer) { 
    while (mustStillWait) { 
     objectUsedAsSynchronizer.wait(); 
    } 
} 

Это было предметом многих других questions.

+0

Извините, но я не понимаю блокировку? – patriques

+0

Я немного отредактировал свой ответ. Также рассмотрите возможность использования некоторых классов параллелизма более высокого уровня в java.util.concurrent. Или посмотрите http://docs.oracle.com/javase/tutorial/essential/concurrency. –

0
t.notify(); 

Вы уведомляете о неверном мониторе. Это исключение возникает, когда вы не обертываете объект монитора с помощью раздела synchronize. Однако объекты, которые вы используете для уведомлений и для методов ожидания, различны. Создайте монитор new Object() и передайте его конструктору Gate.

Также вы можете взглянуть на CountDownLatch, он делает именно то, чего вы пытаетесь достичь.

+0

Спасибо за ответ, может ли этот объект мониторинга быть экземпляром счетчика класса Counter? – patriques

+1

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

1

Вы можете позвонить только wait и notify/notifyAll с synchronized блоков.

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