There are two types of ways to implement Threads in Java.
1. Extends Thread class
2. Implement Runnable
Above answer is based with java 1.5 and prior versions and Threads has more better implementations with 1.5 and later versions.
I am not going to go through those and just look at Thread class Runnable interface.
Both has common functionality. That is to facilitate programmer to write a thread or letting programmer to implement some work within a thread without worrying much about thread mechanism.
So how java let you to do your work in the thread.
Very simple. Java has given run() method.
So whatever you need to do it inside a thread or the work to be done concurrently must be implement inside run() method.
So it is very simple..
So explain in literature... override run() method with concurrent functionality.
So if both these give override over run() method, then why we have two options.
Is it cause one is legacy and other is newer.
Answer is no.
It has more depth. It can be explained with adhere to principles like Open close principle , Liskov substitution .. etc. You can find more details about those principles on the web.
So let's go into detail analysis
First we take Thread class. We can simply create thread by Extends with Thread class. Override run() method. create instance of the class and simply call thread functionality, start() method to run the thread.
Below is an example :
MyThread class is extends Thread class.
I have included constructor with name and set the name for thread with calling super constructor method. This is optional. But with this you can set the name for thread as it creates.
Then we have run() method. This is where logic or the work of the thread resides.
In this thread I have initialized int variable , count
Inside run() method, I increment count and print the value.
So this is an implementation of a "MyThread" thread. you can test with creating instance of "MyThread" and simply calling start() method.
----------------------------------------------------------------------------------------------------
public class MyThread extends Thread {
int count = 0;
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
count++;
System.out.println("MyThread count="+count);
}
}
}
-------------------------------------------------------------------------------------------------------
Below shows testing of MyThread class.
I have created Compare class to test the Mythread class which will be used to compare the Runnable implementation with Thread extension.
--------------------------------------------------------------------------------------------------------
public class Compare {
public static void main(String[] args) {
MyThread t1 = new MyThread("t1");
MyThread t2 = new MyThread("t2");
MyThread t3 = new MyThread("t3");
t1.start();
t2.start();
t3.start();
}
}
-----------------------------------------------------------------------------------------------------------
Out of the Compare class as follows
-----------------------------------------------------------------------------------------------------------
MyThread count=1
MyThread count=1
MyThread count=2
MyThread count=3
MyThread count=1
MyThread count=2
MyThread count=2
MyThread count=3
MyThread count=3
As I have created three threads and one thread print three numbers with starting 1 and ending 3 , thus will have three sets of
MyThread count=1
MyThread count=2
MyThread count=3
as theses are threads, there output may vary. Thread executes asynchronously. that is threads context switch with each other , in simple the execution has no real execution order. Or in other way one thread need not to wait until the finish of other thread - that is the basic need of the thread.
So if we assume all three threads execute successfully, then we need to have 3 occurrences of
MyThread count=1
MyThread count=2
MyThread count=3
where MyThread count=1, MyThread count=2 ,MyThread count=3 may print in different oder each time of Compare main method executes.
For better understand, we can modify our MyThread run() method to print the name of the thread execution. So modification will be as follows.
-----------------------------------------------------------------------------------------------------------
public class MyThread extends Thread {
int count = 0;
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
count++;
System.out.println("MyThread "+Thread.currentThread().getName()+ " count="+count);
}
}
}
-----------------------------------------------------------------------------------------------------------
Output as follows. Note I have given names to threads as t1, t2, t3
You can observe that execution order differ from thread start order.
-----------------------------------------------------------------------------------------------------------
MyThread t2 count=1
MyThread t2 count=2
MyThread t2 count=3
MyThread t3 count=1
MyThread t3 count=2
MyThread t3 count=3
MyThread t1 count=1
MyThread t1 count=2
MyThread t1 count=3
-----------------------------------------------------------------------------------------------------------
If we get another output, it will be totally different.
-----------------------------------------------------------------------------------------------------------
MyThread t1 count=1
MyThread t3 count=1
MyThread t2 count=1
MyThread t2 count=2
MyThread t2 count=3
MyThread t1 count=2
MyThread t1 count=3
MyThread t3 count=2
MyThread t3 count=3
-----------------------------------------------------------------------------------------------------------
I Believe this would give you a clear picture of thread execution at glance, and let's stick to our discussion over creating Thread with extending Thread class Vs Implementation of Runnable.
So we have implemented thread simply with extending a thread class and our work has been implemented inside run() method.
That's it. very simple.
So what's the issue ????
Can you see something with MyThread class ??
it has already one extends, Thread class -- We cannot extends another class
That's a problem we have with Thread extends..
So how to get over with.
Java has given contract , Runnable interface with only run() method
Second way of creating a thread.
Question: Why we need to create a thread ???
Answer : cause we need to do some work in asynchronously ..
OK.override the logic, work in run() method
Question: can we take the run() outside Thread class , so we can extends our thread "in the case MyThread" with specific class and do the thread work separately.
Answer : That's where Runnable comes.
So let's implement same logic using Runnable
-----------------------------------------------------------------------------------------------------------
public class MyRunnable implements Runnable {
int count = 0;
public void run() {
for (int i = 0; i < 3; i++) {
count++;
System.out.println("MyRunnable " + Thread.currentThread().getName()+ " count=" + count);
}
}
}
So we have run() method override
Question: How we are going to run this thread. MyRunnable class does not have any thread functionality. start() method
Answer : Java has given you way
Question: How ???
Answer : we create thread with extends Thread class. it has all functionality of thread implemented inside of it. Why not reuse Thread class
Question: Great .... How to reuse it.
Answer : Thread class has constructor to accept Runnable instance
Question: So we need to create instance of the Runnable and create Thread instance using Thread class
Answer : Yes
Question : We are creating two instances ??
Answer : Yes..
That's how we reuse the functionality.
Question : I don't like creating two instances for create one thread object. Isn't it taking more memory and space ?? I prefer extends Thread class.. So I can straight away start() thread with creating instance.
Answer : We have pros and cons in both ways. Don't be so lazy. Runnable is a better implementation over extends Thread. we can keep thread logic separately and also we can extends another class. Don't you remember the problem we had over extends with Thread where we cannot extends only one class.
Question :Ok. Let's agree Runnable is better .
Answer : You will see more magic in future.
Below Is the execution of Runnable , corresponding to output "MyThread"
main method
----------------------------------------------------------------------------------------------------------------
public class Compare {
public static void main(String[] args) {
MyRunnable myRunnable1 = new MyRunnable();
MyRunnable myRunnable2 = new MyRunnable();
MyRunnable myRunnable3 = new MyRunnable();
Thread r1 = new Thread(myRunnable1, "r1");
Thread r2 = new Thread(myRunnable2, "r2");
Thread r3 = new Thread(myRunnable3, "r3");
r1.start();
r2.start();
r3.start();
}
}
----------------------------------------------------------------------------------------------------------------
Out as below
----------------------------------------------------------------------------------------------------------------
MyRunnable r1 count=1
MyRunnable r1 count=2
MyRunnable r1 count=3
MyRunnable r2 count=1
MyRunnable r2 count=2
MyRunnable r2 count=3
MyRunnable r3 count=1
MyRunnable r3 count=2
MyRunnable r3 count=3
----------------------------------------------------------------------------------------------------------------
So same thing is done using Runnable. But we need to write some additional lines to create instances of Runnable for each thread.
MyRunnable myRunnable1 = new MyRunnable();
MyRunnable myRunnable2 = new MyRunnable();
MyRunnable myRunnable3 = new MyRunnable();
You can simply give the created object as reference as below if needed. Simple java programming way of writing..
-------------------------------------------------------------------------------------------------------------------
public class Compare {
public static void main(String[] args) {
Thread r1 = new Thread(new MyRunnable(), "r1");
Thread r2 = new Thread(new MyRunnable(), "r2");
Thread r3 = new Thread(new MyRunnable(), "r3");
r1.start();
r2.start();
r3.start();
}
}
-------------------------------------------------------------------------------------------------------------------
It will produce same output
-------------------------------------------------------------------------------------------------------------------
MyRunnable r2 count=1
MyRunnable r2 count=2
MyRunnable r2 count=3
MyRunnable r1 count=1
MyRunnable r1 count=2
MyRunnable r1 count=3
MyRunnable r3 count=1
MyRunnable r3 count=2
MyRunnable r3 count=3
-------------------------------------------------------------------------------------------------------------------
So you don't have to worry about additional java code line writing.
So what's the other big deal with Runnable.???
With Runnable You can share the Runnable objet with threads. There by , we can pass process to another thread. Next thread will take upon from previous thread.
May be little confusing. Let's look at with the example.
Here we have created only once instance of Runnable and we have shared with three threads insteads.
Note : Shared
New main method will be looks like this.
we have only one reference "myRunnable" and it is shared with all three threads.
-------------------------------------------------------------------------------------------------------------------
public class Compare {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread r1 = new Thread(myRunnable, "r1");
Thread r2 = new Thread(myRunnable, "r2");
Thread r3 = new Thread(myRunnable, "r3");
r1.start();
r2.start();
r3.start();
}
}
-------------------------------------------------------------------------------------------------------------------
Output will be as follows.
-------------------------------------------------------------------------------------------------------------------
MyRunnable r1 count=1
MyRunnable r1 count=2
MyRunnable r1 count=3
MyRunnable r2 count=4
MyRunnable r2 count=5
MyRunnable r2 count=6
MyRunnable r3 count=7
MyRunnable r3 count=8
MyRunnable r3 count=9
-------------------------------------------------------------------------------------------------------------------
See the output. Now the count is incremented by each time a thread executes.
How this happens.
we have created one Runnable instance/Object. "myRunnable", It is shared with all three threads.
when object is shared its property " count " is shared between threads, thus increment each time run() method executes.
So as a brief following will be the outcomes we must remember when considering Extends Thread over Implment Runnable.
- Java doesn't support multiple inheritance, which means you can only extend one class in Java so once you extended Thread class you lost your chance and can not extend or inherit another class in Java.
- In Object oriented programming extending a class generally means adding new functionality, modifying or improving behaviors. If we are not making any modification on Thread than use Runnable interface instead.
- Runnable interface represent a Task which can be executed by either plain Thread or Executors or any other means. so logical separation of Task as Runnable than Thread is good design decision.
- Separating task as Runnable means we can reuse the task and also has liberty to execute it from different means. since you can not restart a Thread once it completes. again Runnable vs Thread for task, Runnable is winner. Reusability and Seperation.
- Java designer recognizes this and that's why Executors accept Runnable as Task and they have worker thread which executes those task.
- Inheriting all Thread methods are additional overhead just for representing a Task which can can be done easily with Runnable.
We have issues with the Thread and implementation of run() method, what to do if exception happens... how to handle those exceptions... can we return a value...
So next we look at Callable interface , which as some enhance functionality over Runnable.
Callable let's you return from run() method and handle exceptions. Java has change the name to call() - fair enough, that makes a difference and reduce the ambiguity also.
For Quick reviews on states, Threads has 4 different main states. New, Runnable, Running, Dead.
Runnable can be interchange with Running state and
Running state may go to Waiting/Blocked/(Sleep)
New - newly created thread is in this state.
Runnable - once start() method called thread will be in Runnable state
Running - Runnable state will be picked and start executing , state will be Running - where thread actually does it work
Dead - once thread work finish, goes to dead state
Waiting/Blocked(Sleep) - calling sleep, or with some interruption thread will be in Waiting/Blocked state. Once it come out from Waiting or Blocking thread will be in Runnable state.
Note: Thread class has yield() method. This will put Running thread back into Runnable state.
This it is said to be giving fair chance to all threads in the same priority as Yield() thread.
But as sleep(), it is also not guaranteed, same yield() thread may come back to Running straight after Runnable - thus not making fair chance to other threads in same priority.
Although we give the sleep time in millisecond, ex:500 mills , it is not guaranteed that it will be sleep for 500 mills . it can be start Running before after 500 mills.
One important method to remember is join(), where tells JVM to finish join thread before current thread.