Reputation: 887
I've been looking all over the web trying to find information on how static synchronized methods are allowed to be executed. What I found is that a static synchronized method will acquire the class lock. As far as I understand it, this ensures that only one of all the existent class instances will be allowed to execute the static synchronized method. Is this really the case? Can there be 2 class instances executing the static synchronized method concurrently, or not? So, to make it more visual, I'm adding a code-sample.
public class A {
private static synchronized void m1() {
//Print something
}
private synchronized void m2() {
//Print something else
}
}
I understand that, because the static method is acquiring the class level monitor and the non-static method is acquiring the object-level monitor, then both can execute at the same time from 2 different threads like so:
A a = new A;
a.m2();//object-level lock acquired
a.m1();//Class-level lock acquired
However if we have 3 instances of the above class, can they all concurrently run m1()? I think they can't, but I am not sure. So can this happen?
A a = new A;
A aa = new A;
A aaa = new A;
a.m1();
aa.m1();
aaa.m1();
Upvotes: 0
Views: 1003
Reputation: 34628
To clarify a bit more in addition to the other answer:
In general, no two threads can access a static method that is synchronized on the class monitor.
But this doesn't have anything to do with instances of the class itself. You don't need to have instances of the class in order to have threads running that static method. The method is static, so it is available even without an instance of the class. That is, no A
exists in memory, and yet you can access its method.
For example, if your method was public, you could do something like:
public class Test extends Thread {
@Override
public void run() {
A.m1();
}
public static void main( String args[] ) {
Test thread1 = new Test();
Test thread2 = new Test();
thread1.start();
thread2.start();
}
}
Running this Test
class, you'd have two threads, and they would call A.m1()
, and since it's synchronized on the class monitor, they wouldn't be able to do it at the same exact time. But the point here was that there is not even a single object of type A
in memory. They use the static method directly, without creating an instance. No need for instances of A
to run the A.m1()
method!
Now, you made your method private. So you may be thinking that there is no way to use it unless you have instances of A
. But that's not true. You can only use it from the body of the same class, but still, you can write a static method in A that would be able to create two threads (e.g. static nested classes extending Thread
), and those two threads would run A.m1()
, without ever creating a single instance of A
.
That's why we insisted that the rule applies to threads and not to instances of A
. The number of threads has nothing to do with the number of instances.
As for class objects: class objects (like A.class
) are of the type Class
, which is used in Java to represent the class and its capabilities from one level up. You can use it for creating instances of the class without using the word new
, invoking its methods, and many other uses.
So, A
has such a class object, and that object is what holds its monitor for static methods. A class object is created when that class is loaded. And the class is usually loaded when it's needed by the program.
But in certain situations, where there are multiple class loaders in a program, it could happen, theoretically, than two of them loaded the A.class
file (or downloaded it from the net, or got it from some other source, it doesn't matter - only the fact that both of them took the same byte code, that has the same name and package, and loaded it).
In such a case, you may have two classes that have the same name, but Java doesn't see them as the same class. If you get an instance of the one (the equivalent of new A()
) and then of the other one, it will be more or less like having two different classes with the same exact code. In such a case, since as far as Java is concerned, despite having the same name they are not the same class, then you could have one thread running the method m1
of "A #1" and one thread running the m1
of "A #2", and they could do so concurrently.
Upvotes: 0
Reputation: 1074575
As far as I understand it, this ensures that only one of all the existent class instances will be allowed to execute the static synchronized method.
No, it means that one thread will be able to execute the method, and that the synchronization lock is the Class object within a specific class loader.
As it says in the specification:
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.
Can there be 2 class instances executing the static synchronized method concurrently, or not?
"Class instances" is a vague term. If you mean instances of a class, that's irrelevant; this is a static
(class-wide) method, not an instance method. If you mean Class objects, then that's the reason I mentioned class loaders above: In unusual situation where you have more than one class loader, you can have more than one Class object — e.g., copy of the class (not instances of it). If you have more than one Class object, each of those has its own copy of the static
method. And so, since there are two copies synchronized on different objects, one thread can be calling the synchronized
static
method of one of those while another thread is calling the synchronized
static
member of a different one of those.
But that's an edge case. In the normal case, that's not an issue: You only have one copy of the method, and it is synchronized on the one copy of the Class object, and only one thread can be executing it at any given time.
Upvotes: 6