Here is a piece of text I found at this link.
"Avoid lock on static methods
The worst solution is to put the "synchronized" keywords on the static
methods, which means it will lock on all instances of this class."
Why would synchronizing a static method lock all instances of the class? Shouldn't it just lock the Class?
Here's my test code that shows that you're right and the article is a bit over-cautious:
class Y {
static synchronized void staticSleep() {
System.out.println("Start static sleep");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("End static sleep");
}
synchronized void instanceSleep() {
System.out.println("Start instance sleep");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
System.out.println("End instance sleep");
}
}
public class X {
public static void main(String[] args) {
for (int i = 0; i < 2; ++i) {
new Thread(new Runnable() {
public void run() {
Y.staticSleep();
}
}).start();
}
for (int i = 0; i < 10; ++i) {
new Thread(new Runnable() {
public void run() {
new Y().instanceSleep();
}
}).start();
}
}
}
Prints:
Start instance sleep
Start instance sleep
Start instance sleep
Start instance sleep
Start instance sleep
Start static sleep
Start instance sleep
Start instance sleep
Start instance sleep
Start instance sleep
Start instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End instance sleep
End static sleep
Start static sleep
End static sleep
So the static synchronized
has no bearing on the synchronized
methods on the instances...
Of course if static synchronised
methods are used throughout the system, then you can expect them to have the most impact on the throughput of a multithreaded systems, so use them at your peril...
To understand this, the easiest way is to compare how lock works against instance method and static method.
Let's say you have class Test.java, which has two methods as follow.
public class Test{
public synchronized void instanceMethod(){
}
public synchronized static void staticMethod(){
}
}
Meanwhile, there are two instances of class Test, testA and testB. And also there are two thread tA and tB trying to access class Test in parallel.
locking on instanceMethod:
When tA gets the lock on instanceMethod of testA, tB cannot access the the same method in testA, however tB is still free to invoke instanceMethod in testB. Because the synchronization against instanceMethod is instance level locking
locking on staticMethod:
However, when tA gets the lock on staticMethod, the lock has nothing to do with testA or testB, since synchronization on static method is a class level locking. Which means tB cannot access staticMethod at all until tA release the lock
Actually a lock on a static method of class Foo
, is the same as putting a lock on Foo.class
(which is the only instance):
public static void doSomething()
{
synchronized(Foo.class)
{
// ...
}
}
You are right — the actual lock is on the Class
instance itself, not on any instance of the class (let alone all instances) — but I think you're interpreting the linked page too literally. It itself uses the phrase "a static lock (a Class lock)", so clearly its author is aware of how the locking works. But if you have many instances in different threads that are all using synchronized static methods, then those instances will all lock each other out. The synchronized static methods won't cause blocking of synchronized instance methods, but the problem is there regardless.
It doesn't say 'lock all instances of the class'. It says 'lock on all instances of the class. It's poorly worded, indeed incorrect, but it doesn't it say what you said it said.
A synchronized method acquires a monitor (§17.1) before it executes. For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.3.6