themanwhosoldtheworld
themanwhosoldtheworld

Reputation: 570

java synchronizing access to different critical sections

I have a method which looks like the below.

public class CriticalSections
{

    public void mainMethod(boolean b)
        {
            if (b) {
                method1();
            }
            else {
                criticalMethod();
                method2();
            }
        }


        private void criticalMethod()
        {
            System.out.println("in criticalMethod");
        }

        private void method1()
        {
            System.out.println("in method1");
        }

        private void method2()
        {
            System.out.println("in method2");
        }
 }

I need to restrict access to these methods such that

  1. When criticalMethod() is accessed by a thread, access to method1() and method2() should be restricted for all other threads.Similarly when method1() and method2() are being accessed by a thread, access to criticalMethod() should be restricted for all other threads.
  2. method1() can individually be accessed concurrently by different threads.
  3. method2() can individually be accessed concurrently by different threads.
  4. method1() and method2() can be accessed concurrently by different threads.

In order to satisfy the 1st access condition I came up with the following code, but this would not satisfy the other 3 conditions and therefore performance will take a hit.

public class CriticalSections
{

    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();
    private final Lock lock3 = new ReentrantLock();

    public void mainMethod(boolean b)
    {
        if (b) {
            lock1.tryLock();
            try {
                method1();
            }
            finally {
                lock1.unlock();
            }
        }
        else {
            lock1.tryLock();
            try {
                lock2.tryLock();
                try {
                    lock3.tryLock();
                    try {
                        criticalMethod();
                    }
                    finally {
                        lock3.unlock();
                    }
                }
                finally {
                    lock2.unlock();
                }
            }
            finally {
                lock1.unlock();
            }
        }
        lock3.tryLock();
        try {
            method2();
        }
        finally {
            lock3.unlock();
        }
    }

    private void criticalMethod()
    {
        System.out.println("in criticalMethod");
    }

    private void method1()
    {
        System.out.println("in method1");
    }

    private void method2()
    {
        System.out.println("in method2");
    }
}

What should be the synchronization mechanism to be used for satisfying the scenarios mentioned?

Upvotes: 1

Views: 173

Answers (1)

korolar
korolar

Reputation: 1535

What you need is an exclusive lock on criticalMethod and shareable locks on methods method1 and method2. The simplest way to achieve this is to use java.util.concurrent.locks.ReentrantReadWriteLock as below:

public class CriticalSections {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    public void mainMethod(boolean b) {
        if (b) {
            method1();
        } else {
            criticalMethod();
            method2();
        }
    }

    private void criticalMethod() {
        Lock writeLock = lock.writeLock();
        writeLock.lock();
        try {
            System.out.println("in criticalMethod");
        } finally {
            writeLock.unlock();
        }
    }

    private void method1() {
        Lock readLock = lock.readLock();
        readLock.lock();
        try {
            System.out.println("in method1");
        } finally {
            readLock.unlock();
        }
    }

    private void method2() {
        Lock readLock = lock.readLock();
        readLock.lock();
        try {
            System.out.println("in method2");
        } finally {
            readLock.unlock();
        }
    }
}

If you're worried about performance, you can also take a look at java.util.concurrent.locks.StampedLock (Java 8+).

Upvotes: 3

Related Questions