2013-03-27 76 views
0

我有一個程序,模擬蓋茨船舶。他們運行在線程中。這個想法是讓他們在跑步方法的隨機時刻跑步和暫停,以模擬人們經過。這是由所有線程完成的,與此同時,主線程正在等待通知,並在線程通知他們添加了一個通過門的人時檢查船是否已滿,主線程再次檢查船是否已滿。該方案有三類: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; 
     } 
    } 

A閘類:

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(); 
      } 
     } 
    } 

而運行的主要方法的模擬器:

/* 
    * 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"); 
      } 

     } 
    } 

即時得到一個錯誤

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

您必須擁有您呼叫等待或通知對象的監視器。意思是,你必須在synchonize-塊,像

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

這一直是許多其他questions的主題。

+0

對不起,但我不明白的鎖定部分? – patriques 2013-03-27 12:37:34

+0

我編輯了我的答案了一下。還要考慮在java.util.concurrent中使用一些更高級別的併發類。或者查看http://docs.oracle.com/javase/tutorial/essential/concurrency。 – 2013-03-27 12:50:34

0
t.notify(); 

您正在通知錯誤的顯示器。發生此異常時,您不包裝顯示器對象synchronize部分。但是,用於通知和等待方法的對象是不同的。創建new Object()監視器並將其傳遞給Gate的構造函數。

你也可以看看CountDownLatch,它正是你想要達到的。

+0

感謝您的答案,該監視器對象可以是Counter類的計數器實例嗎? – patriques 2013-03-27 12:24:35

+1

任何對象都可以是監視器,但是您必須確保爲使用它的所有線程使用相同的對象。 – 2013-03-27 12:51:26

1

您只能在​​區塊內撥打waitnotify/notifyAll