2017-03-03 23 views
0

最近学んだマルチスレッドの概念を試していましたが、それを実行できませんでした。Javaマルチスレッドコードでエラー-IlegalMonitorExceptionが発生する

IlleagalMonitorStateExceptionが発生しますが、エラーの原因を特定できません。

コード-2の各数値は、充填剤およびwritterスレッドによって追加されたスレッド、参照名フィラー& writter両方が整数との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()']のJavadocを読んでください(https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notifyAll()): "[Throws] IllegalMonitorStateException - 現在のスレッドがこのオブジェクトのモニタの所有者でない場合'this'で同期せずに' notifyAll() 'を呼び出しています。 –

+0

マルチスレッドで学ぶための最良のコンセプトは、 'Object'で低レベルのマルチスレッド化手法を使わないでください。代わりに 'java.util.concurrent'からより高いレベルの構文を使用してください。彼らは、Javaのマルチスレッド化についてより穏やかで便利な入門書を提供します。 –

+0

'final boolean [] numbersCompleted = {false};'は、スレッド間で補完を通知する信頼できる方法ではありません。 'numbersCompleted [0]'への更新が他のスレッドで見えるという保証はありません。 'AtomicBoolean'を使うべきです。 –

答えて

1

:あなたはあなたのリストに同期している

synchronized (integerArrayList) 

お待ちしています/ この曖昧なスレッドオブジェクトの!そしてjavadoc非常に最初の情報としてこう述べています。

は、スレッドがオブジェクトのモニターで待機するように、または指定のモニタを所有せずにオブジェクトのモニターで待機中の他のスレッドを通知しようとしたことを示すためにスローされます。あなたは(待機のすべての使用/通知/ ...)例えば

integerArrayList.wait() 

にそれらを変更したとき

だから、物事は動作するはずです!

そしてヒント:単にはないがあなたの変数の型として、具体的なのimplクラスの型を使用行うだけ

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

のために行く

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

のようなものをしません。またその名前の一部としてではありません!

+0

今、私はどこが間違っていたかわかりません。 –

+0

それは速かった、ありがとう! – GhostCat

関連する問題