Alaa Essam
Alaa Essam

Reputation: 13

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?

Upvotes: 1

Views: 333

Answers (3)

Ravindra babu
Ravindra babu

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+" ");             
            }  
        }           
    }
}
  1. A shared lock is created in main class : RunnableDemo
  2. Two Threads have been created by passing MyRunnable object, which implements Runnable interface. Instead of extending Thread to create new Thread, passing Runnable interface implementation to Thread constructor is preferred approach.
  3. Both Threads have been started. Since they share common lock, only one Thread complete run() block
  4. 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

Pshemo
Pshemo

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

SergeiK
SergeiK

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

Related Questions