Pergunta

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());
Foi útil?

Solução

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top