Static Versus Non-Static Lock Object in Synchronized Block

Static versus non-static lock object in synchronized block

The difference is simple: if the locked-on object is in a static field, then all instances of MyClass* will share that lock (i.e. no two objects will be able to lock on that object at the same time).

If the field 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.

When you use a static lock object:

  • thread 1 calls o1.foo()
  • thread 2 calls o1.foo(), will have to wait for thread 1 to finish
  • thread 3 calls o2.foo(), will also have to wait for thread 1 (and probably 2) to finish

When you use a non-static lock object:

  • thread 1 calls o1.foo()
  • thread 2 calls o1.foo(), will have to wait for thread 1 to finish
  • thread 3 calls o2.foo(), it can just continue, not minding thread 1 and 2

Which one of those you'll need depends on what kind of data you try to protect with your synchronized block.

As a rule of thumb, you want the lock-object to have the same static-ness than the operated-on value. So if you manipulate non-static values only, you'll want a non-static lock object. If you manipulate static values only, you'll want a static lock object.

When you manipulate static and non-static values, then it'll become complicated. The easy way would be to just use a static lock object, but that might increase the size of the synchronized-block more than absolutely necessary and might need to more lock contention than desired. In those cases you might need a combination of static and non-static lock objects.

In your particular case you use the lock in the constructor, which will only ever be executed once per instance, so a non-static lock-object doesn't make any sense here.

Does a static lock object need to be final when using a synchronized(lock object) block?

Using the final in this context is only a good practice.

You can synchronize using any object, final or non final, static or non static.

Using together final and static will give you the security that nobody will synchronize the same code on a different lock. Without using the final you are not sure that somewhere in the code that variable is not reassigned.

Generally speaking using final for a variable that is never reassigned after inited it's a good programming practice. It improves readability because who reads your code knows that this variable will never been reassigned also without reading the full code.

difference between synchronizing a static method and a non static method

I will try and add an example to make this extra clear.

As has been mentioned, synchronized in Java is an implementation of the Monitor concept. When you mark a block of code as synchronized you use an object as a parameter. When an executing thread comes to such a block of code, it has to first wait until there is no other executing thread in a synchronized block on that same object.

Object a = new Object();
Object b = new Object();
...
synchronized(a){
doStuff();
}
...
synchronized(b){
doSomeStuff();
}
...
synchronized(a){
doOtherStuff();
}

In the above example, a thread running doOtherStuff() would block another thread from entering the block of code protecting doStuff(). However, a thread could enter the block around doSomeStuff() without a problem as that is synchronized on Object b, not Object a.

When you use the synchronized modifier on an instance method (a non-static method), it is very similar to having a synchronized block with "this" as the argument. So in the following example, methodA() and methodB() will act the same way:

public synchronized void methodA() {
doStuff();
}
...
public void methodB() {
synchronized(this) {
doStuff();
}
}

Note that if you have a methodC() in that class which is not synchronized and does not have a synchronized block, nothing will stop a thread from entering that method and careless programming could let that thread access non-safe code in the object.

If you have a static method with the synchronized modifier, it is practically the same thing as having a synchronized block with ClassName.class as the argument (if you have an object of that class, ClassName cn = new ClassName();, you can access that object with Class c = cn.getClass();)

class ClassName {
public void static synchronized staticMethodA() {
doStaticStuff();
}
public static void staticMethodB() {
synchronized(ClassName.class) {
doStaticStuff();
}
}
public void nonStaticMethodC() {
synchronized(this.getClass()) {
doStuff();
}
}
public static void unSafeStaticMethodD() {
doStaticStuff();
}
}

So in the above example, staticMethodA() and staticMethodB() act the same way. An executing thread will also be blocked from accessing the code block in nonStaticMethodC() as it is synchronizing on the same object.

However, it is important to know that nothing will stop an executing thread from accessing unSafeStaticMethodD(). Even if we say that a static method "synchronizes on the Class object", it does not mean that it synchronizes all accesses to methods in that class. It simply means that it uses the Class object to synchronize on. Non-safe access is still possible.

static synchronized and non static synchronized methods in threads difference in behavior

Why can Thread 3 just continue without regarding thread 1 and 2.

Because it is locking a different object.

(Unless o1 and o2 happen to refer to the same object ....)

Shouldnt Thread 3 have to wait to acquire the lock on the Object instance 'this' from either thread 1 or 2 before it can proceed ?

Nope. The calls attempt to synchonize on (i.e. lock) o1 and o2 respectively. These will become the this for the respective threads when the foo() method calls start. The this of the respective threads while in the calling context(s) is not relevant.

What happens when a thread tries to call both static and non-static synchronized methods?

The synchronized keyword has two possible uses. It can be used as a modifier for methods, and it can be used as a statement. Besides, the synchronized modifier can be combined with static, and in that case the target object will be the enclosing class instead of the enclosing instance.

Scope    | modifiers           | corresponding statement
---------+---------------------+------------------------
static | synchronized static | synchronized (X.class)
instance | synchronized | synchronized (this)

If a method is static synchronized, the lock is acquired on the class object of the enclosing class, in your case on ThreadExample.class.
Although they're compiled into different byte code, the following two methods are equivalent:

public class Foo {
// static method with synchronized modifer
public static synchronized void foo1() {
// ...
}
// equivalent synchronized statement
public static void foo2() {
synchronized (Foo.class) {
// ...
}
}
}

If a method is synchronized (without static), the lock is acquired on the instance itself. Although they're compiled into different byte code, the following two methods are equivalent:

public class Foo {
// instance method with synchronized modifier
public synchronized void foo3() {
// ...
}
// equivalent synchronized statement
public void foo4() {
synchronized (this) {
// ...
}
}
}

So, increment() and decrement() are synchronized differently, and there can be a race condition.

Therefore, the variable count is not sufficiently protected from concurrent update.

++ and -- cannot be atomic themselves, as incrementing or decrementing a value requires a read-update-write cycle. Technically it could be atomic because some CPUs provide atomicity for that by providing corresponding instructions which will keep the bus / address obtained for themselves until the operation is performed. But the JVM does not rely on such things.

If you need a atomic int, you might want to look at java.util.concurrent.atomic.AtomicInteger.

How to do synchronized in C

synchronized is implemented with the VM environment methods MonitorEnter() and MonitorExit().

Pitfalls

When you use the synchronized modifier, you synchronize on something which is more or less public, i.e. visible to other objects and classes as well. The Monitor feature of java.lang.Object which provides the underlying facility for synchronized is public, as well as the native functions MonitorEnter() / MonitorExit() and the wait pool methods wait(), notify() and notifyAll(). This can lead to unexpected bugs and deadlocks if "somebody else" is also using "your object / your class" for synchronization.

Therefore it has become a pattern to actually not use the synchronized modifier but instead use synchronized statements on a private lock object, like this:

public class Foo {
private final Object lock = new Object();
public void foo() {
synchronized (lock) {
// ...
}
}
}

Now Foo can no longer be disturbed or blocked by somebody else synchronizing on it. You might think there might be a reasonable use case for that, but I think if you have a use case for locking across object / class boundaries, there's probably a big flaw in the design - things are not self-contained enough.

If you need a class lock instead of an instance lock, just make the variable static.

Note that when doing serialization, you will have to take care of the lock object. The simplest way is to actually not use Object, but this:

public class Lock implements Serializable {}

If you want to save serialization storage, you can declare the lock transient and recreate the lock during deserialization, but be careful about transient final, you need reflection or readResolve() for them, but that's a different story.

Does the lock on a static synchronized method affect the non-static synchronized methods of it's instances?

A static synchronized method will acquire the lock on the Class instance for the class. A synchronized method will acquire the lock on this. When you acquire the class level lock by calling a synchronized static method, the object-level locks are not affected.

synchronized blocks for static and non-static methods

Globally, there exists one instance of the thing called StaticNonStaticTest.object. Whenever you synchronize on that thing (regardless where from), you are synchronizing on the same lock.

static synchronized and non static synchronized methods in threads

The lock objects are different on the static method and non-static method. The static method uses the Class object as the lock (lock obj: MyClass.class), while the non-static method uses the instance object as the lock to which the invocation of the method at that time is bound (lock obj: this).



Related Topics



Leave a reply



Submit