Synchronizing overlapping sets of methods

167 Views Asked by At

Imagine a Java class with three methods:

  1. master()
  2. foo()
  3. bar()

I want to synchronize master() and foo() and also master() and bar(), without synchronizing foo() and bar(). It can be done will a separate lock for every pair of synchronized methods, but my actual code has many more than three methods so I was hoping there's a way to do it without so many lock objects.

3

There are 3 best solutions below

10
On BEST ANSWER

You are essentially describing a ReadWriteLock. Every two methods are allowed to run simultaneously (a "read lock"), except for master(), which excludes all others (a "write lock"):

public class MyClass {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock r = rwLock.readLock();
    private final Lock w = rwLock.writeLock();

    public void master() {
        w.lock();
        // do stuff
        w.unlock();
    }

    public void foo() {
        r.lock();
        // do stuff
        r.unlock();
    }

    public void bar() {
        r.lock();
        // do stuff
        r.unlock();
    }
}
1
On

You can use synchronized on any Object. So, you can create a separate lock for the methods:

public class Lock {
    private final Object master_foo = null;
    private final Object master_bar = null;
    public void master() {
        synchronized(master_foo) {
            synchronized(master_bar) {
                ...
            }
        }
    }

    public void foo() {
        synchronized(master_foo) {
            ...
        }
    }

    public void bar() {
        synchronized(master_bar) {
            ...
        }
    }
}
1
On

I would go with Mureinik's answer, but just for the heck of it, here's another way you can set up read/write synchronization (untested):

public class Test {

    private final Semaphore semaphore = new Semaphore(Integer.MAX_VALUE);

    public void master() {
        semaphore.acquireUninterruptibly(Integer.MAX_VALUE);
        try {
            //...
        } finally {
            semaphore.release(Integer.MAX_VALUE);
        }
    }

    public void foo() {
        semaphore.acquireUninterruptibly();
        try {
            //...
        } finally {
            semaphore.release();
        }
    }

    public void bar() {
        semaphore.acquireUninterruptibly();
        try {
            //...
        } finally {
            semaphore.release();
        }
    }

}