Java 多线程代码报错-IllegalMonitorException

Java Multithread code gives error-IllegalMonitorException

我正在尝试最近学习的一些多线程概念,但无法 运行。

它给出了 IlleagalMonitorStateException 但没有弄清楚它发生的原因。

所以关于代码 2 线程引用名称填充程序和编写器都共享一个数组列表填充程序正在用整数填充数组列表(但将填充它最多 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();

这里:

synchronized (integerArrayList) 

您正在同步您的 列表

但是您 waiting/notify 在 this 的匿名线程对象上!正如 第一个 javadoc 中的信息所说:

抛出以指示线程已尝试在对象的监视器上等待或通知其他线程在对象的监视器上等待而不拥有指定的监视器。

所以当您将它们更改为

时,事情应该会起作用
integerArrayList.wait()

例如(wait/notify/...的所有用法)!

并提示:不要做类似

的事情
final ArrayList<Integer> integerArrayList = new ArrayList<>();

就去

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

只需不要使用具体实现class类型作为变量的类型;而且也不作为其名称的一部分!