I am replicating a classroom using Threads there are a few conditions that need to be set up
Studentcan not enter or leave when aLectureris in the room- A
Lecturercan not start the class until allStudentshave 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 Classroomclass 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.