Can we have multiple static locks in a class in java - 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 ?

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.

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.

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.

Related

In which cases we need to synchronize a method?

Let's say I have the following code in Java
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
}
And I create two threads T1 and T2
Thread T1 = new Thread(c1);
Thread T2 = new Thread(c2);
Where c1 and c2 are two different instances of the class SynchronizedCounter.
It is really needed to synchronize the method increment? Because I know that when we use a synchronized method, the thread hold a lock on the object, in this way other threads cannot acquire the lock on the same object, but threads "associated" with other objects can execute that method without problems. Now, because I have only one thread associated with the object c1, it is anyway needed to use the synchronized method? Also if no other threads associated with the same object exist?
In your specific example, synchronized is not needed because each thread has its own instance of the class, so there is no data "sharing" between them.
If you change your example to:
Thread T1 = new Thread(c);
Thread T2 = new Thread(c);
Then you need to synchronize the method because the ++ operation is not atomic and the instance is shared between threads.
The bottom line is that your class is not thread safe without synchronized. If you never use a single instance across threads it doesn't matter. There are plenty of legitimate use cases for classes which are not thread safe. But as soon as you start sharing them between threads all bets are off (i.e. vicious bugs may appear randomly).
Given code/example does not need synchronization since it is using two distinct instances (and so, variables). But if you have one instance shared between two or more threads, synchronization is needed, despite comments stating otherwise.
Actually it is very simple to create a program to show that behavior:
removed synchronized
added code to call the method from two threads
public class SynchronizedCounter {
private int c = 0;
public void increment() {
c++;
}
public static void main(String... args) throws Exception {
var counter = new SynchronizedCounter();
var t1 = create(100_000, counter);
var t2 = create(100_000, counter);
t1.start();
t2.start();
// wait termination of both threads
t1.join();
t2.join();
System.out.println(counter.c);
}
private static Thread create(int count, SynchronizedCounter counter) {
return new Thread(() -> {
for (var i = 0; i < count; i++) {
counter.increment();
}
System.out.println(counter.c);
});
}
}
Eventually (often?) this will result in weird numbers like:
C:\TMP>java SynchronizedCounter.java
122948
136644
136644
add synchronized and output should always end with 200000:
C:\TMP>java SynchronizedCounter.java
170134
200000
200000
Apparently posted code is not complete: the incremented variable is private and there is no method to retrieve the incremented value. impossible to really know if the method must be synchronized or not.

Determining which thread got the synchronized key

I am learning how to work with threads and I ran into this question that with a given code I need to say what whether a certain thread will or will not be able to access a certain function.
Here is the code :
public class InsideClass{}
public class SyncClass{
private InsideClass in1;
private InsideClass in2;
public SyncClass(InsideClass i, InsideClass i2){ in1 = i; in2 = i2; }
public synchronized void func1() { System.out.println("in func1"); }
public void func2() { synchronized(in1) { System.out.println("in func2"); }}
public static synchronized void func3() { System.out.println("in func3"); }
public void func4() { synchronized(in2) { System.out.println("in func4"); }}
public synchronized void func5() {
synchronized(in1) {
synchronized(in2){ System.out.println("in func5"); }}
}}
public class MyThread extends Thread{
private SyncClass sc;
public MyThread(SyncClass s) {
sc = s;
}
public void run(){
sc.func1();
sc.func2();
SyncClass.func3();
sc.func4();
sc.func5();
}
}
public class Sys {
public static void main(String[] args) {
InsideClass in1 = new InsideClass();
InsideClass in2= new InsideClass();
SyncClass s1 = new SyncClass(in1,in2);
SyncClass s2 = new SyncClass(in2,in1);
MyThread t1 = new MyThread(s1);
MyThread t2 = new MyThread(s2);
t1.start();
t2.start();
}
}
The question goes like this, assuming that t1 is preforming task(i) (i=1,2,3,4), will t2 be able to preform func(i+1) or will it get blocked? explain.
I wrote the full question just in case it wasn't clear.
1) Assuming that t1 is preforming func1
a) Will t2 be able to preform func1?
b) Will t2 be able to preform func2?
c) Will t2 be able to preform func3?
d) Will t2 be able to preform func4?
2) Assuming that t1 is preforming func2.
a) Will t2 be able to preform func2?
b) Will t2 be able to preform func3?
c) Will t2 be able to preform func4?
3) Assuming that t1 is preforming func3
a) Will t2 be able to preform func3?
b) Will t2 be able to preform func4?
4) Assuming that t1 is preforming func4
a) Will t2 be able to preform func4?
5) func5 has a unique implementation.
a) How many different locks are cought by this method? Specify who they are.
b) What is the problem that comes up at func5? How would you solve this problem?
I'm not looking for answers to all these questions (even though it would be nice just in case) , but I would like to get an explanation of what is the meaning of an object (in this example in1/in2) inside a synchronized block, when 2 other object are initialized with these objects (s1,s2). If t1 is preforming func1 which is synchronized, how does that effect the attempt to preform func2? (how does the fact that s1 and s2 were initialized with the same objects inflect this issue).
I hope my question was clear enough. Thanks!
A synchronized statement acquires the intrinsic lock of the given object, then performs its body, and then releases the lock.
Object lock = new Object();
synchronized(lock) {
...body...
}
The Java Runtime Environment (JRE) will never allow two threads to acquire the intrinsic lock of the same object at the same time. If one thread acquires the lock, then the second thread to attempt it will be blocked until the first thread releases the lock.
It's important to know that the lock will be released no matter how the thread exits the ...body.... It doesn't matter whether it returns, whether it breaks, whether it simply runs off the end, or whether it throws an exception. The lock will be released in any case.
There's a shortcut way to write a member function whose entire body is synchronized.
This:
class MyClass {
synchronized void foobar(...args...) { ...body... }
}
Means exactly the same as this:
class MyClass {
void foobar(...args...) {
synchronized(this) { ...body... }
}
}
And the same goes for a synchronized static function, except that it synchronizes on the class object instead.
This:
class MyClass {
synchronized static void foobar(...args...) { ...body... }
}
Means exactly the same as this:
class MyClass {
static void foobar(...args...) {
synchronized(MyClass.class) { ...body... }
}
}
It's important to remember the difference between a variable and an object. Two threads can enter a synchronized(foo){...} block at the same time if the variable foo refers to two different objects in the two different contexts. (Think carefully about your in1 and in2 member variables!) Likewise, two different threads can call the same synchronized member function at the same time if the two threads are operating on different objects. (Your example has two different instances of SyncClass!)
The code as stands does not compile.
func5 has three open brackets followed and three close brackets
There is no close bracket to then close the class.
If you have a compiler please compile the code and post again.

Synchronized statements -- create objects to provide locks so update of c1 wouldn't interleave with update of c2

I'm new to Java and is trying to learn the concept of Synchronized statements. I saw the paragraph and the code below from Java Tutorial Oracle. My question is
1) Under what kind of circumstances does update of c1 interleaves with update of c2.
2) How does the object 'lock1' and 'lock2' prevent update of c1 interleaves with the update of c2.
I'm really struggling to understand the concept.
Synchronized statements are also useful for improving concurrency with
fine-grained synchronization. Suppose, for example, class MsLunch has
two instance fields, c1 and c2, that are never used together. All
updates of these fields must be synchronized, but there's no reason to
prevent an update of c1 from being interleaved with an update of c2 —
and doing so reduces concurrency by creating unnecessary blocking.
Instead of using synchronized methods or otherwise using the lock
associated with this, we create two objects solely to provide locks.
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
The implication is that there might be other threads using the same MsLunch object. For example, you might start two threads like so:
MsLunch ml = new MsLunch();
Thread thread1 = new Thread() {
public void run() { while (true) ml.inc1(); }
};
Thread thread2 = new Thread() {
public void run() { while (true) ml.inc2(); }
};
thread1.start();
thread2.start();
There are now two threads running in parallel, one that calls inc1() in a loop and another that calls inc2() in a loop.
By having separate locks for these two methods the two threads won't slow each other down. If you had a shared lock then inc1() and inc2() wouldn't be able to run at the same time. Any time you called one the other would block until the first call finished.
Thread thread3 = new Thread() {
public void run() { while (true) ml.inc2(); }
};
Contrast this to what happens if you add a third thread that also calls inc2(). Thread #1 is free to call inc1() as fast as it likes. Meanwhile, threads #2 and #3 both want to call inc2(), so they will fight each other to do so. If thread #2 is calling inc2() then thread #3 will block until that call finishes. And vice versa, if thread #3 is in the middle of a call then thread #2 will have to wait.
When you have a synchronized method :
public synchronized void inc1() {
c1++;
}
It is implicitly converted to :
public void inc1() {
synchronized(this) {
c1++;
}
}
SO, if you make both inc1 and inc2 synchronized methods, then they both need to get hold of the current object (this) monitor and then increment.
But since c1++ and c2++ are independent, they should not be blocked because we are using a single lock. What we must ensure is that multiple calls to inc1() and inc2() should be blocked in seperate sandboxed ways i.e, an access to inc1() by thread 1 should not block access to inc2() by thread-2. Having different locks will do this.

Static synchronized methods and non-synchronized static methods confusion

I have a small confusion. Please have a look at the code below.
public class ThreadDemo {
//non-static synchronized method
synchronized void a(){
actBusy();
}
//static synchronized method
static synchronized void b(){
actBusy();
}
//static method
static void actBusy(){
try{
Thread.sleep(1000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
final ThreadDemo x = new ThreadDemo();
final ThreadDemo y = new ThreadDemo();
Runnable runnable = new Runnable() {
public void run() {
int option = (int) (Math.random() * 4);
switch (option){
case 0: x.a();
break;
case 1: x.b();
break;
case 2: y.b();
break;
case 3: y.b();
break;
}
}
} ;
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
}
}
I know for sure that invocation of this sequence is possible.
x.a() //in Thread-1
y.b() //in Thread-2
Though still I have a small confusion that, we can easily see x.a() also calls actBusy() method
which is a
static method. Method b() is a static synchronized method calling a non-synchronized
static method. When thread-2 gets a class level lock, the why call of actBusy() from Thread-1
is not blocked?
I am just logically confused, if a thread gets a class level lock, that class other
non-synchronized static methods remain open to be called from other methods (instance method). Why?
then why call of actBusy() from Thread-1 is not blocked?
Since your actBusy method is NOT synchronized. Even if you acquired class level lock you can invoke non-synchronzied static methods.
The point of marking the methods as synchronized is to enable locks. Only methods declared as synchronized are subjects to these locks. So if you acquired a lock (suppose class level lock) then any non-synchronized method acts as before and isn't aware of lock being acquired. This allows you to decide which methods need to be blocked and which don't.
static synchronized method has a lock on the class object, while non static synchronized method has a lock on the instance object (this) - so both methods can be invoked concurrently, and one thread will run 1 while the other run the 2nd.
However, note that there is no race condition available in your code, because race condition requires a write, and such does not exist in these methods.
actBusy() is itself not synchronized but the callers methods are.
So Thread 1 does not block as it acquires lock on this object and no other thread holds lock on this, so it is able to call it without any problem.
That is because the non-static synchronized method locks on this the present instance and not on class object.
x.a() grabs a lock on the present instance i.e x and no other thread will be able to enter method a() of x until the present the present thread releases the lock.
Thread 1 --> x.a() //acquires lock and holds it
Thread 2 ---> x.a() //blocks here until Thread 1 releases lock on x
EDIT:
Class Object != Instance
So according to JMM they are different objects and two threads don't interfere with each other. So it allows you to call it.
EDIT 2:
why does it allow calls to other static methods? Any logic behind it?
Suppose this:
public static synchronized int statefulMethod(){
//this should be protected
}
public static int nonStatefulMethod(){
//Just returns a static value such as 5
//so this is thread safe as it does not have any state
}
public static synchronized int otherStatefulMethod(){
//this should also be thread safe
}
So if thread 1 is in method statefulMethod() which is having some shared state to protect so it uses class level lock. Now thread 2 calls nonStatefulMethod() then it should not logically block as that method is thread safe and there is no point in making that thread block here.
Now if thread 3 calls the otherStatefulMethod() while thread 1 is holding class lock then thread 3 will have to wait as that method is also static-synchornized.
Lock objects are not hierarchical. Therefore obtaining a lock on the class itself does not supersede locks on instances of your class. They are separate lock objects and will only block code that attempts to lock on exactly that same object.
So if a thread enters a static synchronized method, the only threads that will be blocked are those also trying to enter a static synchronized method on the same class. Threads that are merely trying to enter an non-static synchronized method are unaffected - they are only competing against threads trying to enter non-static synchronized methods on that same object instance.
Regarding your comment below - only static methods marked synchronized are subject to the class level lock. If you want other static methods to be blocked, you must also mark them synchronized.
Why is this the case? Well, it would be rather presumptuous for the compiler to assume you need to lock all your static methods simply because one is marked as synchronized. It is assumed that the programmer knows which methods must be synchronized in order to ensure thread safety.

Why does this NOT cause a dead-lock

Why does the following piece of code not cause a deadlock?
From my limited understanding of multi-threading programming, when getBar1() is called, sharedBuffer would be 'locked', hence, when the method tries to call getBar2(), the thread would have to wait for sharedBuffer (which is held by itself!). In other words, getBar2() cannot return until getBar1() has (and released sharedBuffer). But on the other hand, getBar1() cannot return either because it is waiting for getBar2() to return.
==> Deadlock. (But in actuality, it is not, which is why I am confused)
...
Foo sharedBuffer = new Foo();
Bar1 getBar1()
{
Bar1 bar1;
synchronized (sharedBuffer)
{
bar1 = sharedBuffer.getBar1();
if (bar1 == null)
bar1 = new Bar1(sharedBuffer, getBat2());
sharedBuffer.setBar1(bar1);
}
return bar1;
}
Bar2 getBar2()
{
Bar2 bar2;
synchronized (sharedBuffer)
{
bar2 = sharedBuffer.getBar2();
if (bar2 == null)
bar2 = new Bar2();
}
return bar2;
}
...
Java's monitors are recursive, meaning that the same thread can acquire the same locks several times.
From the JLS (§17.1 Synchronization):
A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.
A deadlock happens when concurrent operations attempt to lock two or more resources in a different order, and they are both stuck waiting for the resource locked by the other.
For example, threads T1 and T2 synchronize on resources R1 and R2:
T1 synchronizes on R1.
scheduler decides that T2 should run
T2 synchronizes on R2.
T2 attempts to synchronize on R1; it's forced to wait until T1 relinquishes the lock.
scheduler sees that T2 can't continue running, so allows T1 to run
T1 attempts to synchronize on R2; it's forced to wait until T2 relinquishes the lock.
neither thread can proceed
What you're doing here is basic synchronization, only allowing one object to access sharedBuffer at a time.
It doesn't deadlock because you really only have a single lock. In both functions, you're locking on sharedBuffer. When the first thread calls getBar1(), it locks on sharedBuffer. When the same thread calls getBar2(), it hits the synchronized block and already has the lock so it just enters the lock.
If you want to cause a deadlock, use two different values against which to lock. Then, you'll only see it if the timing lines up properly. If you want to force a deadlock, make sure the first thread sleeps long enough for the second thread to get a lock.
Here's some code that will deadlock... (untested, prolly has typos). This should work because a different thread has the lock than the one that wants the lock.
public class Deadlock extends Thread
{
private Deadlock other;
private String name;
public static void main(String[] args)
{
Deadlock one = new Deadlock("one");
Deadlock two = new Deadlock("two");
one.setOther(two);
two.setOther(one);
one.start();
two.start();
}
public setOther(Deadlock other){ this.other = other; }
public void run() {
deadlock();
}
public synchronized deadlock() {
System.out.println("thread " + this.name + " entering this.deadlock()");
sleep(1000); // adjust as needed to guarantee deadlock
System.out.println("thread " + this.name + " calling other.deadlock()");
other.deadlock(this.name);
System.out.println(name + " - deadlock avoided!");
}
}

Categories

Resources