Reputation: 13
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?
Upvotes: 1
Views: 333
Reputation: 38910
Below is the modified code to handle your issue.
public class RunnableDemo {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread (new MyRunnable(lock));
Thread t2 = new Thread (new MyRunnable(lock));
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable {
Object lock = new Object();
public MyRunnable(Object lock){
this.lock = lock;
}
@Override
public void run () {
synchronized(lock){
for (int i = 0; i <13; i++) {
System.out.print(i+" ");
}
}
}
}
RunnableDemo
MyRunnable
object, which implements Runnable
interface. Instead of extending Thread
to create new Thread
, passing Runnable
interface implementation to Thread
constructor is preferred approach. Thread
complete run()
block Now you can see output is in right sequence as below:
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
I have just showcases basic locking mechanism. For advanced version of multi threading, you can refer to high level concurrency tutorial.
Upvotes: 0
Reputation: 124215
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, ..).
Upvotes: 1
Reputation: 345
You can not be sure that threads start simultaneously unless you use synchronizers like Semaphore
, CountDownLatch
or CyclicBarrier
.
synchronized
keyword itself is used to protect the same object (method or block of code) from concurrent access. In your code synchronized
is useless.
Upvotes: 0