Mohit Patidar
Mohit Patidar

Reputation: 179

Can we have multiple static locks in a class in java

I have multiple methods on which I would like to have static lock so that no two objects can access one method but at the same time different methods do not get locked with those object and can run independently.

class A {
    private static final A lock1 = new A();
    private static final B lock2 = new B();

    public void method1() {
        synchronized (lock1) {
            // do something
        }
    }

    public void method2() {
        synchronized (lock2) {
            // do something
        }
    }
}

Now I want these two methods to be independent of each other when it gets locked but at the same time I want multiple instances of same class to be locked at single method.

How can this be achieved ? By using different class ? Can this be achieved by doing just this ?

Upvotes: 2

Views: 950

Answers (3)

Burak Serdar
Burak Serdar

Reputation: 51542

First, this is sufficient:

private static final Object lock1 = new Object();
private static final Object lock2 = new Object();

Then, with your implementation, method1 and method2 are independent of each other, but only one instance of method1 or method2 can run among all instances of A. If you want to allow different concurrent instances of A so that method1 and method2 of different instances can run concurrently, just declare the locks without static.

In other words: if a1 and a2 are instances of A:

  • with static locks, if a1.method1 is running, a2.method1 cannot be run by another thread
  • without static, a1.method1 can be run by only one thread. a1.method1 and a2.method1 can run concurrently.

Upvotes: 4

Solomon Slow
Solomon Slow

Reputation: 27125

Locks aren't for methods. Locks are for data. The whole purpose of using a mutex lock is to ensure that different threads will always see a consistent view of some shared data.

Your code example shows two locks, but it doesn't show the data that the locks are supposed to protect. This is better:

class Example {
    // R-State variables
    private final Object lockR = new Object();
    private A a = ...;
    private B b = ...;
    private C c = ...;

    // G-State variables
    private final Object lockG = new Object();
    private Alpha alpha = ...;
    private Beta beta = ...;
    private Gamma gamma = ...;

    public void methodR() {
        synchronized (lockR) {
            // do something with a, b, and c.
        }
    }

    public void methodG() {
        synchronized (lockG) {
            // do something with alpha, beta, and gamma.
        }
    }
}

My Example class has two independent groups of variables; a, b, and c, and alpha, beta, and gamma. Each independent group has its own independent lock. Any method that accesses any of the "R-State" variables should be synchronized (lockR)..., and likewise for the "G-State" variables and lockG.

If a method needs access to both groups at the same time, then it must lock both locks. But NOTE! That could be a sign that the two groups aren't really independent. If there is any dependency between them, then there really should be just one lock.


Also note, I removed static from the example. That was a purely gratuitous change. I abhor static. You should abhor it too, but that's a different subject that has nothing to do with locking.

Upvotes: 1

Maneesha Indrachapa
Maneesha Indrachapa

Reputation: 905

Static Lock
If the locked-on object is in a static field, then all instances of that particular Class will share that lock. It means that if one object created from that class is accessing that static lock, another object created from that class can not access that lock.

Non-static Lock
If the class has a lock that is non-static, then each instance will have its own lock, so only calls of the method on the same object will lock each other.

As an example when you use a static lock object:

  • thread 1 calls obj01.doSomething()
  • thread 2 calls obj01.doSomething(), will have to wait for thread 1 to finish
  • thread 3 calls obj02.doSomething(), will also have to wait for thread 1 (and probably 2) to finish.

When you use a non-static lock object:

  • thread 1 calls obj01.doSomething()
  • thread 2 calls obj01.doSomething(), will have to wait for thread 1 to finish
  • thread 3 calls obj02.doSomething(), it can just continue, not minding threads 1 and 2, because this is a new object and it does not depend on the class.

non-static locks are basically object-level Locks. static locks are class level Locks

Object Level Lock
Every object in Java has a unique lock. If a thread wants to execute a synchronized method on a given object, first it has to get a lock of that object. Once the thread got the lock then it is allowed to execute any synchronized method on that object. Once method execution completes automatically thread releases the lock.

public class Example implements Runnable {

    @Override
    public void run() {
        objectLock();
    }
    public void objectLock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(this) {
            System.out.println("Synchronized block " + Thread.currentThread().getName());
            System.out.println("Synchronized block " + Thread.currentThread().getName() + " end");
        }
    }
    public static void main(String[] args) {
        Example test1 = new Example();
        Thread t1 = new Thread(test1);
        Thread t2 = new Thread(test1);
        Example test2 = new Example();
        Thread t3 = new Thread(test2);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

The output will be,

t1
t3
Synchronized block t1
t2
Synchronized block t1 end
Synchronized block t3
Synchronized block t2
Synchronized block t3 end
Synchronized block t2 end

Class Level Locks
Every class in Java has a unique lock which is nothing but a class level lock. If a thread wants to execute a static synchronized method, then the thread requires a class level lock. Once a thread got the class level lock, then it is allowed to execute any static synchronized method of that class. Once method execution completes automatically thread releases the lock.

public class Example implements Runnable {

    @Override
    public void run() {
        classLock();
    }
    public static void classLock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(Example.class) {
            System.out.println("Synchronized block " + Thread.currentThread().getName());
            System.out.println("Synchronized block " + Thread.currentThread().getName() + " end");
        }
    }
    public static void main(String[] args) {
        Example test1 = new Example();
        Thread t1 = new Thread(test1);
        Thread t2 = new Thread(test1);
        Example test2 = new Example();
        Thread t3 = new Thread(test2);
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

The output will look like below,

t1
t3
t2
Synchronized block t1
Synchronized block t1 end
Synchronized block t2
Synchronized block t2 end
Synchronized block t3
Synchronized block t3 end

Current Scenario

In here you have two methods and if one method is accessed using one lock and the other is using another lock, with your implementation you can have two objects using each other methods but never the same method.

obj01.method01();
obj02.method02();

this is possible,but not this

obj01.method01();
obj02.method01();

you obj02 has to wait till obj01 finish the method.

Upvotes: 0

Related Questions