Reputation: 7069
I have one question about thread. I have following Thread class and creating 2 thread objects.
public class MyThread extends Thread{
String name="";
public MyThread(String string) {
name=string;
}
@Override
public void run() {
callMe();
}
synchronized private void callMe() {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
a.start();
b.start();
}
}
When I execute this , output I get is -
Started
Started
B = 1
B = 2
A = 1
A = 2
B = 3
A = 3
B = 4
A = 4
B = 5
A = 5
I know that A and B are printed randomly as Thread Scheduler picks it up.
But my question is: why loop is NOT executed one after other? I have used synchronized
keyword.
Upvotes: 4
Views: 296
Reputation: 3762
Because 2 threads are executing through 2 different objects.
All right, you must have by now realized from the other answers. You are creating 2 separate objects, viz. a and b. Now, when you call the start method, a new thread is started to execute through the run method of the respective (separate not same) objects. The synchronization is indeed on the method but there is exactly one thread running through the callMe method of a and exactly one thread running through callMe method of b. So your expectation that the output should be:
A - 1 A - 2 A - 3 ...
is not happening.
Hope this helps
Upvotes: 2
Reputation: 10628
Synchronized works per Object. To synchronize across instances you need a shared object to synchronize on.
I.e.
private final static Object globalLock = new Object();
// Later
private void callMe() {
synchronized (globalLock) {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
Upvotes: 9
Reputation: 968
Your Code is equal to this Code
private void callMe(){
synchronized(this){
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
You just synchronise to the current Object. If you want to synchronise them to each other your need to synchronise to the class, like this :
private void callMe(){
synchronized(MyThread.class){
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
Upvotes: 3
Reputation: 1499760
Your synchronized
method is effectively:
private void callMe() {
synchronized(this) {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(name+" = "+i);
}
}
}
Now you've created two different instances, so this
will be different for each thread... so they're not synchronizing against each other. If you want to see two threads working with the same monitor, you could rewrite your code like this:
public final class DemoRunnable implements Runnable {
@Override
public synchronized void run() {
System.out.println("Started");
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " = " + i);
}
}
public static void main(String[] args) {
Runnable runnable = new DemoRunnable();
Thread a = new Thread(runnable, "A");
Thread b = new Thread(runnable, "B");
a.start();
b.start();
}
}
Then you'll get output like this:
Started
A = 1
A = 2
A = 3
A = 4
A = 5
Started
B = 1
B = 2
B = 3
B = 4
B = 5
(Although it could be the other way round, of course.)
We still have two threads, but they're calling a synchronized method on the same object (a DemoRunnable
in this case) so one will have to wait for the other to complete.
A few points:
Runnable
is generally preferred over extending Thread
; it's more flexibleThread
object has its own issues, as the Thread
class does it itself; try to avoid itthis
anyway - I would usually have a private final variable of type Object
to represent a monitor that only my code knows about... that way I can easily see all the code that could synchronize on it, which makes it easier to reason aboutUpvotes: 13