Yassen Mohamed Yassen Mohamed - 25 days ago 6
Java Question

synchronized keyword in java

I create a two threads

a1
,
a2
from class A that extends Thread class. Class A declare two constructors and run method that is synchronized. When I write the code in this form the two thread sometimes start at the same time although the
run
method is declared as synchronized and I am getting result like

0 0 1 1 2 3 4 5 6 7 2 8 3 9 4 10 5 11 6 12 7 8 9 10 11 12


Code:

public class Main {
public static void main(String[] args) {
A t = new A () ;
A a1 = new A (t) ;
A a2 = new A (t) ;

a1.start();
a2.start();
}
}

class A extends Thread {
public A() {
super() ;
}

public A(Thread th ) {
super(th) ;
}
@Override
public synchronized void run () {
for (int i = 0; i <13; i++) {
System.out.print(i+" ");
}
}
}


But when I create two threads via class Thread not A,

Thread a1 = new Thread (t);
Thread a2 = new Thread (t);


the synchronized method
run
work and two threads do not start at the same time always giving result

0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 3 4 5 6 7 8 9 10 11 12


My question: Why synchronized keyword do not work when I create a two thread from class A (although I define a two constructors) and work when I create a two thread from Thraed class?

Answer Source

When you run thread by calling start() at some point it invokes its run() method which in Thread class looks like this:

public void run() {
    if (target != null) {
        target.run();
    }
}

This code is responsible for executing code from run method of Runnable target object passed in new Thread(Runnable target) constructor.

But you overrode Thread#run() in your A class. So now start() method invokes A#run (because of polymorphism), which means it never invokes target.run() (in your case - t.run() since t was passed as A thread target).
Now even if A#run method is synchronized, because each thread invokes it on separate instance (thread object itself) no synchronization happens because threads are not using common lock/monitor.

You ware getting correct results only because sometimes one thread was able to do its full work before other started.


To avoid such confusing problems (and many other) don't extend Thread at all. Create class which implements Runnable and pass it to Thread instance.

Think of Runnable as task, and Thread as worker which should execute that task. Your job is to describe what worker should do (take this, put it there), not how (bend your knees, grab that, ..).