Java Threads - Creating, Starting and Running them
Ways to create a new thread of execution
In Java, there are two ways to create a new thread of execution
- By extending java.lang.Thread class.
- By implementing java.lang.Runnable interface.
Runnable
interface is implemented by the Thread class.- A common protocol for all the objects that wish to execute in a different thread (than the calling thread) is to implement Runnable interface.
Subclass or Runnable - which is better?
- Always prefer the use of Runnable over Thread. Here are the reasons.
- A class implementing Runnable interface can simply pass itself to create a Thread instance and can run thereafter. This eliminates the need of extending the Thread class for the purpose of executing the code in a separate thread.
- When extending the Thread class, we’re not overriding any of its methods. Instead, we override the method of Runnable (which Thread happens to implement). This is a clear violation of IS-A Thread principle
- Creating an implementation of Runnable and passing it to the Thread class utilizes composition and not inheritance – which is more flexible
- After extending the Thread class, we can’t extend any other class. Java doesn’t support multiple inheritance, which means we can only extend one class. So, if our class extends Thread class, that class cannot extend another class in Java. With Runnable interface, our class can implement Runnable interface and additional interfaces if necessary.
- From Java 8 onwards, Runnables can be represented as lambda expressions
- 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.
- Reuse Separating task as Runnable means we can reuse the task and also has liberty to execute it from different means. We can not restart a Thread once it completes. So, when we look at it from reuse perspective, Runnable is winner.
- Java designer recognizes this and that’s why Executors accept Runnable as Task and they have worker threads which execute the tasks.
- 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 then use Runnable interface instead. Inheriting all Thread methods are additional overhead just for representing a Task which can can be done easily with Runnable.
- When having the Runnable’s executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses.
- Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool.
Calling run() Instead of start() in Thread class is a common pitfall
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
Why do we need to call start()
method of thread?
What is difference by calling start()
over run()
method in java thread?
Implement thread either overriding run()
method of Thread
class or implementing Runnable
interface and than calling start()
method on thread.
start()
method calls run()
method internally.
start
public void start()
Causes this thread to begin execution; the JVM calls the run
method of this thread.
The result is that two threads are running concurrently: the current thread (which returns from the call to the start
method) and the other thread (which executes its run
method).
- The start() call will return as soon as the thread is started.
- It will not wait until the run() method is done.
- The run() method will execute as if executed by a different CPU.
- When the run() method executes it will print out the text “MyThread2 running”.
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
run
public void run()
If this thread was constructed using a separate Runnable.run()
object, then that Runnable
object’s run()
method is called; otherwise, this method does nothing and returns.
Subclasses of Thread should override this method.
What happens if we call Thread.run() instead of calling Thread.start()?
Thread newThread = new Thread(MyRunnable());
newThread.run(); //should be start();
At first, we may not notice anything because the Runnable's run()
method is executed like we expecte. However, it is NOT executed by the new thread we just created. Instead the run()
method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run()
method of the MyRunnable
instance called by the new created thread, newThread, you MUST call the newThread.start()
method.