I am replicating a classroom using Threads there are a few conditions that need to be set up
Student
can not enter or leave when aLecturer
is in the room- A
Lecturer
can not start the class until allStudents
have sat - Students can not leave until the lecture is over
A Classroom
is a shared class between Students and Lecturers
so this is where I have put my Conditions
to make the Threads wait.
I am confused to where the Conditions should go, should they go in the Classroom
class as they are going to be used in both of the Lecturer/Student
class to notify().
I am getting java.lang.IllegalMonitorStateException in all the classes in the error report
Exception in thread "Thread-6" java.lang.IllegalMonitorStateException at java.base/java.lang.Object.notify(Native Method) at Classroom.allSeated(Classroom.java:87) at Student.sitDown(Student.java:70) at Student.run(Student.java:38) Exception in thread "Thread-0" java.lang.IllegalMonitorStateException at java.base/java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:149) at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1302) at java.base/java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:439) at Classroom.waitToStartClass(Classroom.java:78) at Lecturer.startClass(Lecturer.java:43) at Lecturer.run(Lecturer.java:25)
Classroom
import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Classroom { private String name; private int capacity; private Semaphore teacherInRoom; // Binary Semaphore for Lecturer in a room private Semaphore semaphoreStudentVisitor;// Counting Semaphore for Visitors/Students in a room set to the capacity private Lock lock= new ReentrantLock(); private Condition startClass = lock.newCondition(); private Condition classOver = lock.newCondition();; private boolean lecturerInRoom; private boolean allSitting; private boolean lectureStart; private int enteredStudents = 0; public Classroom(String name, int capacity) { this.name = name; this.capacity = capacity; this.teacherInRoom = new Semaphore(1);// Control Lecturer in room this.semaphoreStudentVisitor = new Semaphore(capacity);// The amount of student allowed in a room at a time this.lecturerInRoom = false; this.allSitting = false; this.lectureStart = true; } // Name of room public String getName() { return name; } // Checks to see if the lecturer has entered the room public boolean checkIfLecturerInRoomStudent() { return lecturerInRoom; } // Check to see if students are all sitting public boolean checkIfStudentsAreSitting() { return allSitting; } // Check to see the number of students who have entered public int numberOfStudentsInRoom() { return enteredStudents; } // Check to see if lecture has started public boolean haslectureStarted() { return lectureStart; } // Used to make the Lecturer wait on the condition startClass public void waitToStartClass() { try { while(!checkIfStudentsAreSitting()) { try { startClass.await(); }catch (InterruptedException e) {} } }finally { lock.unlock(); } } // THIS IS WHERE THE java.lang.IllegalMonitorStateException is thrown // Called to notify the Lecturer that all of the students are sitting public void allSeated() { lock.lock(); try { startClass.notify(); }finally { lock.unlock(); } } // Controls the semaphores for the room // No more threads than room capacity // No more than 1 lecturer per room public void lecturerSemaphoreEntered() { try { lecturerInRoom = true; teacherInRoom.acquire(); } catch (InterruptedException e) {} } public void lecturerSemaphoreLeave() { teacherInRoom.release(); lecturerInRoom = false; } public void studentVisitorsSemaphoreEntered() { try { semaphoreStudentVisitor.acquire(); enteredStudents++; } catch (InterruptedException e) { // TODO: handle exception } } public void studentVisitorsSemaphoreLeave() { semaphoreStudentVisitor.release(); enteredStudents--; } // Create a random index for the classroom to enter static int classRoomNumber (int lengthOfArray) { Random rand = new Random(); int roomNumber = rand.nextInt(lengthOfArray); return roomNumber; } }
Lecturer
import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Lecturer extends Thread{ private final String name; private Classroom classroomList []; private Lock lock = new ReentrantLock(); public Lecturer(String name, Classroom [] classroom) { this.name = name; this.classroomList = classroom; } @Override public void run() { while(true) { int timeInRoom = (int) (Math.random() * 10000); Classroom classroom = classroomList[Classroom.classRoomNumber(classroomList.length)]; // Create random number for room to enter enter(classroom); startClass(classroom); leave(classroom); } } //Calls the methods in Classroom for semaphores and condition private void enter(Classroom classroom) { classroom.lecturerSemaphoreEntered(); } private void leave(Classroom classroom) { classroom.lecturerSemaphoreLeave(); } private void startClass(Classroom classroom) { classroom.waitToStartClass(); } }
The error also occurs here when sitDown()
is called
Students
import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Student extends Thread{ private Classroom classroomList[]; static volatile int sitting = 0; volatile Lock lock = new ReentrantLock(); public Student(Classroom[] classroomList) { this.classroomList = classroomList; } @Override public void run() { while(true) { int timeInRoom = (int) (Math.random() * 5000); Classroom classroom = classroomList[Classroom.classRoomNumber(classroomList.length)]; if(!classroom.checkIfLecturerInRoomStudent()) { enter(classroom); if(classroom.checkIfLecturerInRoomStudent()) { // Counting so all of the students can sit while(sitting < classroom.numberOfStudentsInRoom()) { sitting++; } //Here all students are sitting sitDown(classroom); } sitting = 0; leave(classroom); } } } // Uses the Semaphore in the Classroom to control the students in the room // also it increments the number of current students synchronized void enter(Classroom classroom) { classroom.studentVisitorsSemaphoreEntered(); } // Uses the Semaphore in the Classroom to control the students in the room // also it decrements the number of current students synchronized void leave(Classroom classroom) { classroom.studentVisitorsSemaphoreLeave(); } // Uses the Semaphore in the Classroom to control the students in the room // also it decrements the number of current students synchronized void sitDown(Classroom classroom) { classroom.allSeated(); } }
Advertisement
Answer
The Exception is been threw because you are calling the method notify of condition, outside of a synchronized block. This method is from the Object class, you need to call signal or signalAll which is the method of Condition to notify.