javamultithreadingillegalmonitorstateexcep

Java Multithread code gives error-IllegalMonitorException


I was trying some concepts of multithreading learned recently but was not able to run it.

It gives IlleagalMonitorStateException but does not figure out the error why it is happening.

So about code-2 threads-reference names-filler & writter both are sharing an arraylist-filler is filling arraylist with integer(but will fill it upto 30) and after each number is added by filler and writter thread read the arraylist get the item writes it to file remove it from arraylist. For better understanding comment is added to code.

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();

Solution

  • Here:

    synchronized (integerArrayList) 
    

    You are synchronizing on your list.

    But you are waiting/notify on this of your anonymous thread objects! And as the very first information in the javadoc says:

    Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

    So things should work when you change those to

    integerArrayList.wait()
    

    for example (all usage of wait/notify/...) !

    And hint: don't do things like

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

    just go for

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

    Simply do not use the concrete impl class type as type of your variable; and also not as part of its name!