11

While reading through the significant difference between Thread and Runnable from here, I encountered a difference that is:

When you extends Thread class, each of your thread creates unique object and associate with it. where as

When you implement Runnable, it shares the same object to multiple threads..

There is code give :

class ImplementsRunnable implements Runnable {

  private int counter = 0;

  public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
  }
}

 class ExtendsThread extends Thread {

   private int counter = 0;

   public void run() {
     counter++;
     System.out.println("ExtendsThread : Counter : " + counter);
   }
 }

 public class ThreadVsRunnable {

   public static void main(String args[]) throws Exception {
     //Multiple threads share the same object.
     ImplementsRunnable rc = new ImplementsRunnable();
     Thread t1 = new Thread(rc);
     t1.start();
     Thread.sleep(1000); // Waiting for 1 second before starting next thread
     Thread t2 = new Thread(rc);
     t2.start();
     Thread.sleep(1000); // Waiting for 1 second before starting next thread
     Thread t3 = new Thread(rc);
     t3.start();

     //Creating new instance for every thread access.
     ExtendsThread tc1 = new ExtendsThread();
     tc1.start();
     Thread.sleep(1000); // Waiting for 1 second before starting next thread
     ExtendsThread tc2 = new ExtendsThread();
     tc2.start();
     Thread.sleep(1000); // Waiting for 1 second before starting next thread
     ExtendsThread tc3 = new ExtendsThread();
     tc3.start();
   }
 }

The output is something like this:

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

It proves differences given above. I make a slight modification in code given below:

class ImplementsRunnable implements Runnable {

  private int counter = 0;

  public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
  }
}

class ExtendsThread extends Thread {

  private int counter = 0;

  public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
  }
}

public class ThreadVsRunnable {

  public static void main(String args[]) throws Exception {
    //Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    //Modification done here. Only one object is shered by multiple threads here also.
    ExtendsThread extendsThread = new ExtendsThread();
    Thread thread11 = new Thread(extendsThread);
    thread11.start();
    Thread.sleep(1000);
    Thread thread12 = new Thread(extendsThread);
    thread12.start();
    Thread.sleep(1000);
    Thread thread13 = new Thread(extendsThread);
    thread13.start();
    Thread.sleep(1000);
  }
}

Now the output is :

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 2
ExtendsThread : Counter : 3

I understand the fact that, here same object (extendsThread) is shared by three threads. But I'm confused here that how it is different from implementing Runnable. Here, even if *ExtendsThread * extends Thread, we are still able to share the object of this class to other threads. In my thinking the above difference does not make any sense.

Thanks.

helderdarocha
  • 23,209
  • 4
  • 50
  • 65
Balwant Kumar Singh
  • 1,158
  • 4
  • 24
  • 48
  • @helderdarocha This has been given as solution there. There are conflict between Rupesh Yadav and zEro. I just want to know, how the above difference make sense ? – Balwant Kumar Singh Feb 19 '14 at 04:53
  • 1
    the confusion comes from your source; when you implement runnable, you *can* share the object between threads. But you rarely would do this. You could also do this with a thread since it is a runnable anyway, but that would be even weirder. – Joeri Hendrickx Feb 19 '14 at 13:12

3 Answers3

10

Here's what the javadoc states

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started. For example, a thread that computes primes larger than a stated value could be written as follows:

The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started. The same example in this other style looks like the following:

So the two ways

public class MyThread extends Thread {
    // overriden from Runnable, which Thread implements
    public void run() {
        ...
    }
}

...
MyThread thread = new MyThread();
thread.start();

Or

public class MyRunnable implements Runnable{
    public void run() {
        ...
    }
}
...
Thread thread = new Thread(new MyRunnable());
thread.start();

Your counter field is an instance field.

In your first case, each of the objects created here

 ExtendsThread tc1 = new ExtendsThread();
 tc1.start();
 Thread.sleep(1000); // Waiting for 1 second before starting next thread
 ExtendsThread tc2 = new ExtendsThread();
 tc2.start();
 Thread.sleep(1000); // Waiting for 1 second before starting next thread
 ExtendsThread tc3 = new ExtendsThread();
 tc3.start();

will have their own copy (that's how instance variables work). So when you start each thread, each one increments its own copy of the field.

In your second case, you are using your Thread sub class as a Runnable argument to the Thread constructor.

ExtendsThread extendsThread = new ExtendsThread();
Thread thread11 = new Thread(extendsThread);
thread11.start();
Thread.sleep(1000);
Thread thread12 = new Thread(extendsThread);
thread12.start();
Thread.sleep(1000);
Thread thread13 = new Thread(extendsThread);
thread13.start();
Thread.sleep(1000);

It is the same ExtendsThread object that you pass, so its counter field gets incremented by all threads. It's pretty much equivalent to your previous usage of ImplementsRunnable.

To add from the comments:

First thing to understand is that the Thread class implements Runnable, so you can use a Thread instance anywhere you can use Runnable. For example,

new Thread(new Thread()); // won't do anything, but just to demonstrate

When you create a Thread with

new Thread(someRunnable);

and start it, the thread calls the given Runnable instance's run() method. If that Runnable instance happens to also be an instance of Thread, so be it. That doesn't change anything.

When you create a custom thread like

new ExtendsThread();

and start it, it calls run() on itself.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • @Sotirious Delimanolis SO, the above difference is not relevant?? – Balwant Kumar Singh Feb 19 '14 at 04:56
  • @BalwantChauhan Can you clarify which above difference you are referring to? – Sotirios Delimanolis Feb 19 '14 at 04:58
  • @Sotirious Delimanolis Sure. It is, When you extends Thread class, each of your thread creates unique object and associate with it. where as When you implement Runnable, it shares the same object to multiple threads.. – Balwant Kumar Singh Feb 19 '14 at 05:00
  • 1
    @BalwantChauhan First thing to understand is that the `Thread` class implements `Runnable`, so you can use a `Thread` instance anywhere you can use `Runnable`. When you create a `Thread` with `new Thread(someRunnable)` and start it, the thread executes the given `Runnable` instance's `run()` method. If that `Runnable` instance happens to also be an instance of `Thread`, so be it, that doesn't change anything. When you create a custom thread like `new ExtendsThread()` and start it, it calls `run()` on itself. – Sotirios Delimanolis Feb 19 '14 at 05:03
  • @SotiriosDelimanolis Can I say, by passing thread's reference as parameter it just copying the old instance's value to new instance? therefore output is `1,2,3` – Asif Mushtaq Oct 01 '15 at 19:17
3

The principle difference in implementing Runnable is that you do not 'consume' your single inheritance. Consider these Class declarations:

public class HelloRunnable implements Runnable extends AbstractHello

public class HelloRunnable extends Thread

You can do more with Runnable when it comes to inheritance.

Manuel
  • 3,828
  • 6
  • 33
  • 48
jeremyjjbrown
  • 7,772
  • 5
  • 43
  • 55
1

@BalwantChauhan: One common usage of Runnable interface is that as we know that multiple inheritance is not possible in case of Java. Now suppose you have a scenario where you want extends a class and also you want to implement thread. So for those scenario if we go ahead for Thread then it is not possible to achieve it. For example : Suppose (in case of Java Swing), if you want to create a frame and also in that frame class you want to implement thread, then it is not possible to extends JFrame and Thread class so in that case we extends JFrame and implement Runnable.

public class HelloFrame extends JFrame implements Runnable{

  ...

  public void run(){
    //  thread code
  }

  ...
}  
Suneet Bansal
  • 2,664
  • 1
  • 14
  • 18