I have this class, which is a basic approach to a file locking utility (doesn't interact with the locks from the OS tho). The idea is to have a static HashMap which stores pair of references to File objects that are used by the application with binary semaphores. Upon first access to a new file the pair is stored into the variable. The problem is that the .wait() line throws IllegalMonitorStateException, and I can't understand why, because I've created a project to test this class with only one thread, so it's impossible that the thread accessing the method doesn't own the object, isn't it?
public abstract class FileLocker {
private static final HashMap<File, Semaphore> locksMap = new HashMap<>();
public synchronized static final void getLock(final File file) {
if (!FileLocker.locksMap.containsKey(file)) {
FileLocker.locksMap.put(file, new Semaphore(1, Boolean.TRUE));
}
try {
FileLocker.locksMap.get(file).wait();
} catch (final InterruptedException e) {
SysLogger.log(e, "ERR0", SysLogger.Level.CRASH);
}
if (file.isDirectory()) {
for (final File f : file.listFiles()) {
if (f.isDirectory()) {
FileLocker.getLock(f);
}
}
}
}
public synchronized static final void releaseLock(final File file) {
if (file.isDirectory()) {
for (final File f : file.listFiles()) {
if (f.isDirectory()) {
FileLocker.releaseLock(f);
} else {
FileLocker.locksMap.get(file).notify();
}
}
}
FileLocker.locksMap.get(file).notify();
}
}
My intention was that the methods weren't synchronized, but since I started receiving this exception, I changed them to synchronized so they theoretically make sure that the thread entering them owns the resources used, but it's not working, the same exception arises.
Exception trace:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at org.lsp.io.files.FileLocker.getLock(FileLocker.java:18)
at org.lsp.main.Main.main(Main.java:9)
Called with
FileLocker.getLock(Paths.get("default.xml").toFile());
FileLocker.locksMap.get(file).wait();
should be
FileLocker.locksMap.get(file).acquire();
wait
in this case is waiting on the Object monitor. Since you are not synchronized on the semaphore ie:
Semaphore s = FileLocker.locksMap.get(file);
synchronized(s){
s.wait();
}
you get your exception. The acquire
is offered by Semaphore and handles that synchronization for you.
Note You'll also run into the same situation with notify()
instead of release()