Java - synchronizing static methods
Asked Answered
D

6

12

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?

Dermatitis answered 11/3, 2013 at 1:4 Comment(6)
Since static methods are available to all instances, it locks all instances.Fowlkes
Although static methods are available to instances, they shouldn't be accessed via instances. They should only be accessed statically. So what the author says still isn't right.Dermatitis
@Fowlkes No, it doesn't lock any instances. 'synchronized(this)' would proceed during this lock.Khaki
The dangers of quoting out of context. Reading through the whole text it becomes very clear that the author is talking about what happens when multiple threads try to access the same static synchronized method. The POV is not the object instances, its the threads.Pannell
@Fowlkes 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.Purvey
@RobertChristian. Great. Well worth the three year wait.Fowlkes
M
7

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...

Masuria answered 11/3, 2013 at 1:25 Comment(1)
Thanks for the test code! Even being over-cautious shouldn't make what the author says right. Instance and class locks are separate. The article had me doubting the hallowed SCJP, especially since the author, from his CV, is an expert.Dermatitis
U
35

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

Un answered 11/3, 2013 at 1:16 Comment(6)
Very good explanation of the difference in locking mechanisms.Some
Finally got the idea about static synchronized method. Nice explanation.Triode
Yeah this is a pretty good summary of the locking instance vs static methods.Feed
I'm not sure I like this explanation. You are saying "tA gets the lock on instanceMethod of testA" which isn't true to my knowledge. Shouldn't it be that tA obtains the lock on the instance testA. It doesn't lock on a method of an instance.Dorathydorca
Seems the 2 methods are the same, so i would probably edit the last sentence of the last paragraph. I would write: "Which means tB cannot access any methods until tA release the lock"Unrighteous
Can you please show whole code?Mazman
Q
8

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)
    {
        // ...
    }
}
Quinn answered 11/3, 2013 at 1:14 Comment(0)
M
7

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...

Masuria answered 11/3, 2013 at 1:25 Comment(1)
Thanks for the test code! Even being over-cautious shouldn't make what the author says right. Instance and class locks are separate. The article had me doubting the hallowed SCJP, especially since the author, from his CV, is an expert.Dermatitis
L
4

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.

Latvian answered 11/3, 2013 at 1:15 Comment(0)
K
2

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.

Khaki answered 11/3, 2013 at 1:50 Comment(0)
P
2

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

Purvey answered 10/2, 2016 at 23:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.