Even though the lock is held by the Writer thread, the following exception occurs when the below-mentioned code is run.
Writer has entered the critical section! Message: stay strong through your pain Lock held! Exception in thread "Writer" java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method)
public class Buffer {
private StringBuilder text;
private final int MAX_PERMITS;
private ReentrantLock writerLock = new ReentrantLock();
private Semaphore semaphore;
public Buffer(int maxPermits) {
text = new StringBuilder();
MAX_PERMITS = maxPermits;
semaphore = new Semaphore(MAX_PERMITS);
}
public void write(String message) throws InterruptedException {
writerLock.lock();
System.out.println(ANSI_BLUE + Thread.currentThread().getName() + " has entered the critical section! Message: " + message);
text.append(message); text.append(". ");
Thread.sleep(2000);
if(writerLock.isHeldByCurrentThread()) {
System.out.println(ANSI_BLUE+"Lock held!");
writerLock.notifyAll();
}
writerLock.unlock();
}
public void read() throws InterruptedException{
if(text.length()==0) return;
writerLock.lock();
semaphore.acquire();
System.out.println(ANSI_GREEN+Thread.currentThread().getName()+" read the following message: "+text.toString());
semaphore.release();
writerLock.unlock();
}
}
Explicit locks such as ReentrantLock are essentially a separate type of locking to the implicit 'synchronised' locks. In other words, locking/unlocking a ReentrantLock is a separate scheme to the synchronized/wait/notify scheme. So you need to decide which scheme you want to use:
The problem with your code is essentially that you're trying to "mix and match" between the two schemes.
The advantage of the explicit Condition is that you can create different Conditions and therefore make it clear in your code what the actual reason (condition) is that you are signalling/waiting for. You can also decide whether the lock is 'fair' or not.
Disadvantages of an implicit synchronized lock include: