Reputation: 179
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
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
:
static
locks, if a1.method1
is running, a2.method1
cannot be run by another threada1.method1
can be run by only one thread. a1.method1
and a2.method1
can run concurrently.Upvotes: 4
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
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:
obj01.doSomething()
obj01.doSomething()
, will have to wait for thread 1 to finishobj02.doSomething()
, will also have to wait for thread 1 (and probably 2) to finish.When you use a non-static lock object:
obj01.doSomething()
obj01.doSomething()
, will have to wait for thread 1 to finishobj02.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