2017-03-03 47 views
0

我正在嘗試最近學到的多線程的一些概念,但無法運行它。Java多線程代碼給出錯誤 - IllegalMonitorException

它給IlleagalMonitorStateException但沒有找出錯誤發生的原因。

所以關於代碼2的線程參考名稱填充&編寫者都共享arraylist填充正在填充arraylist與整數(但將填充到30),並在每個數字添加填充和寫入線程後讀取arraylist獲取該項目將其寫入文件從arraylist中刪除它。爲了更好的理解評論被添加到代碼中。

package com.utsav.pratice; 

import java.io.*; 
import java.util.ArrayList; 

public class Main { 

    public static void main(String[] args) throws FileNotFoundException { 
     //shared arraylist-synchronized 
     ArrayList<Integer> integerArrayList = new ArrayList<>(); 
     //writter will write to this file numbers added to arraylist by filler and than will remove it from arraylist 
     FileOutputStream file = new FileOutputStream("Numbers.txt"); 
     //filler will mark it true after completing all numbers 
     final boolean[] numbersCompleted = {false}; 

     Thread filler=new Thread(new Runnable(){ 
      @Override 
      public void run(){ 
       //1-30 numbers one by one will be written to Arraylist 
       for (int i = 1; i < 31; i++) { 
        synchronized (integerArrayList) { 
         //if arraylist is not empty that means writter not performed on arraylist hence invoking wait to release lock so writter could perform 
         while(!integerArrayList.isEmpty()){ 
          try { 
           wait(); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 
         } 
         //so arraylist is empty now lets fill it,notify that releasing lock and than put thread to sleep 
         integerArrayList.add(i); 
         System.out.println("Number added"); 
         if(i==30){ 
          numbersCompleted[0] =true;} 
         notifyAll(); 
        } 
        try { 
         Thread.sleep(2000); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println("Numbers adding completed"); 
      } 
     }); 

     Thread writter=new Thread(new Runnable(){ 
      @Override 
      public void run(){ 
       //if numbers are completed than nothing to write come out of loop 
       while(!numbersCompleted[0]) { 
        synchronized (integerArrayList) { 
         //if arraylist is empty than its time for filler to work hence putting thread to wait so lock could be released for filler 
         while (integerArrayList.isEmpty()){ 
          try { 
           wait(); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 
         } 
         //so arraylist is not empty now lets write it & than remove it from arraylist,notify that releasing lock and than put thread to sleep 
         try (DataOutputStream fileWritter = new DataOutputStream(new BufferedOutputStream(file));) { 
          fileWritter.writeInt(integerArrayList.get(0)); 
          System.out.println("Random number written"); 
         } catch (IOException e) { 
          e.printStackTrace(); 
         } 
         integerArrayList.remove(0); 
         notifyAll(); 
        } 
        try { 
         Thread.sleep(2000); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println("File written completely"); 
      } 
     }); 

     //starting both threads-2cases filler takes the key-ok(will fill & wait) or filler takes the key(will wait since will be empty) 
     writter.start(); 
     filler.start(); 
+1

[閱讀'notifyAll()'](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notifyAll())的Javadoc:「[引發] IllegalMonitorStateException - 如果當前線程不是此對象監視器的所有者。「你正在調用'notifyAll()'而不同步'this'。 –

+0

在多線程中學習的最佳概念是:不要嘗試在Object上使用低級多線程方法;改爲使用來自'java.util.concurrent'的高級構造。他們將對Java中的多線程進行更加溫和和有用的介紹。 –

+0

請注意''final boolean [] numbersCompleted = {false};'不是線程之間完成信號完成的可靠方法。不能保證更新'numbersCompleted [0]'在其他線程中可見。你應該使用'AtomicBoolean'。 –

回答

1

這裏:

synchronized (integerArrayList) 

你是你名單上同步。

但是您正在等待/通知您的匿名線程對象!而作爲javadoc第一個信息說:

拋出的異常表明某一線程已經試圖等待對象的監視器,或者不擁有指定的監控,通知其他線程正在等待對象的監視器上。

所以事情,當你改變那些

integerArrayList.wait() 

例如(等待所有使用/通知/ ...)應該工作!

而且提示:不要做這樣的事情

final ArrayList<Integer> integerArrayList = new ArrayList<>(); 

只是去

List<Integer> numbers = new ArrayList<>(); 

根本就沒有使用具體的實現類類型爲類型的變量;也不是它的名字的一部分!

+0

好吧,先生,現在我不知道我錯了。 –

+0

很快,謝謝! – GhostCat