Многопоточный код Java дает ошибку-IllegalMonitorException
Я пробовал некоторые концепции многопоточности, изученные недавно, но не смог их запустить.
Это дает IlleagalMonitorStateException, но не выясняет ошибку, почему это происходит.
Так что о коде-2 thread-reference names-filler и writer оба совместно используют arraylist-filler заполняет arraylist целым числом (но будет заполнять его до 30) и после того, как каждый номер будет добавлен filler, а поток писателя прочитает 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 ответ
Вот:
synchronized (integerArrayList)
Вы синхронизируете в своем списке.
Но вы ждете / уведомите об этом ваши анонимные объекты потока! И как говорится в самой первой информации в Javadoc:
Брошенный, чтобы указать, что поток попытался ждать на мониторе объекта или уведомить другие потоки, ожидающие на мониторе объекта, не имея указанного монитора.
Так что все должно работать, когда вы меняете их на
integerArrayList.wait()
например (все использование wait/notify/...)!
И подсказка: не делай такие вещи, как
final ArrayList<Integer> integerArrayList = new ArrayList<>();
просто пойти на
List<Integer> numbers = new ArrayList<>();
Просто не используйте конкретный тип класса impl как тип вашей переменной; а также не как часть его имени!