最近学んだマルチスレッドの概念を試していましたが、それを実行できませんでした。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();
['notifyAll()']のJavadocを読んでください(https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notifyAll()): "[Throws] IllegalMonitorStateException - 現在のスレッドがこのオブジェクトのモニタの所有者でない場合'this'で同期せずに' notifyAll() 'を呼び出しています。 –
マルチスレッドで学ぶための最良のコンセプトは、 'Object'で低レベルのマルチスレッド化手法を使わないでください。代わりに 'java.util.concurrent'からより高いレベルの構文を使用してください。彼らは、Javaのマルチスレッド化についてより穏やかで便利な入門書を提供します。 –
'final boolean [] numbersCompleted = {false};'は、スレッド間で補完を通知する信頼できる方法ではありません。 'numbersCompleted [0]'への更新が他のスレッドで見えるという保証はありません。 'AtomicBoolean'を使うべきです。 –