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
Drawing an Object Using Getgraphics() Without Extending Jframe
Java Error - Actual and Formal Argument Lists Differ in Length
Java Regex Capturing Groups Indexes
Why Java.Util.Optional Is Not Serializable, How to Serialize the Object with Such Fields
Order of Loading Jar Files from Lib Directory
How to Get My Maven Integration Tests to Run
Dealing with an Arraystoreexception
<Form Action="/Sampleservlet" Giving Me Exception
How to Use Jsch for Ssh Key-Based Communication
Drawing a Simple Line Graph in Java
Java, Simplified Check If Int Array Contains Int