Java Runnable Example
In this example, we will take a look into the Runnable interface in Java, and how it can be used in association with the Thread
class to create and execute new threads in your program. We will also try to explain what a Runnable
is and what’s the difference from Thread
, as well as take a look into the different ways that you can implement Runnable in your code.
1. Runnables and Threads
Let’s start by talking about a very common confusion in Java. Runnables are NOT Threads. The Runnable
interface is used to define a certain task that we want to execute, and the whole implementation of this task is inside its only method, run()
(which accepts no arguments). The Runnable class by itself does not create a separate thread, because this is what Thread actually does.
Thread
is used to create a new execution path (a new thread), separate from the main program. By providing a Runnable as an argument to a Thread constructor, you are essentially giving access of the Runnable’s task (defined in the run()
method), to a new Thread object. At any time during your program, you can start the new thread, by using Thread.start()
and the Runnable’s code will start running.
2. Why use Runnable?
Although you have the ability to create new threads by using just the Thread
class, which by itself implements the Runnable
interface, the suggested and much more accepted approach is to use Runnable for all the logic that we want to provide for our threads. There are certain reasons for that:
- Modularity: When you run a thread and it finishes running, there is no way to restart it. This could lead to a lot of code duplication in case of multithreading, where you need a certain task to run a number of times. Fortunately, you can create a Runnable instance which can be reused in any number of threads.
- Ease of use:
Runnable
only has one method,public void run()
. It accepts no arguments and is as simple as possible.Thread
has many methods that need to be taken into account making it very cumbersome to work with, and the extra overhead is always an issue. - Inheritance: More often than not, you will have to use additional classes (through inheritance) to extend the functionality of your Runnable object. Java does not support multiple inheritance, so it is much more convenient to create a new class which just
implements Runnable
(and allows to extend another class) than creating a new class thatextends Thread
and prevents you from inheriting anything else.
3. Runnable implementation and example
There are two ways to implement a Runnable in Java. Let’s take a quick look into them:
- Inheritance: You can create a class which implements the
Runnable
interface. You will be forced to implement therun()
method, which contains the logic/code of the task, and instantiate it in the standard Java way. You can use pass this as an argument to aThread
instance, as explained above. - Anonymous inner class: In some cases you need to run a small snippet of only a few lines of code. In that case, you can always create a new anonymous inner class inside the
Thread
constructor and implement therun()
method there as well. This is of course not modular, and you cannot reuse that code.
Let’s take a look at the code and see both of these ways at work!
MyRunnableImplementation.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | package com.javacodegeeks.runnableexample; public class MyRunnableImplementation implements Runnable { // We are creating anew class that implements the Runnable interface, // so we need to override and implement it's only method, run(). @Override public void run() { // We are creating a simple loop which will run and allow us to take // a look into how the different threads run. for ( int i = 0 ; i < 5 ; i++) { // Thread.currentThread().getName() is used to get the name of the // currently running thread. We can provide a name, if we create // the thread ourselves, else it will be given one from the JVM. System.out.println(Thread.currentThread().getName() + "\twith Runnable: MyRunnableImplementation runs..." + i); } } } |
As you can see, we create a class that implements the Runnable
interface. In the main program, we will instantiate this class and pass it as an argument to a Thread
constructor, which will run the task, which in this context is the loop.
RunnableExampleMain.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package com.javacodegeeks.runnableexample; public class RunnableExampleMain { public static void main(String[] args) { System.out.println( "Executing program..." ); // Create a new instance of our class that implements the Runnable interface. // This class can be provided as an argument to a Thread instance. MyRunnableImplementation r = new MyRunnableImplementation(); // Create a new Thread instance, provide the task that we want to run // (by providing the Runnable as an argument) and give the thread a name. // Now we can use Thread.start() to run it! Thread thread1 = new Thread(r, "Thread 1" ); thread1.start(); // We are creating a second thread. Take notice that we are // providing the same Runnable, so this thread will run the same task // as the first one. Thread thread2 = new Thread(r, "Thread 2" ); thread2.start(); // Create a thread and provide the Runnable argument as an anonymous inner class. // Since we are creating the class "on the spot", we need to provide the implementation // of the run() method here. // This way is faster and more compact, but it lacks reusability. Thread thread3 = new Thread( new Runnable() { @Override public void run() { // We are doing the same thing as with the MyRunnableImplementation class for ( int i = 0 ; i < 5 ; i++) { System.out.println(Thread.currentThread().getName() + "\twith Runnable: Inner class Runnable runs..." + i); } } }, "Thread 3" ); thread3.start(); } } |
Take notice here, that we can use the same Runnable
on more than one Thread
, without an issue. Also, we can implement the Runnable anonymously inside the constructor.
3.1 Java Runnable Example – Output
We have to take into consideration the fact that we are talking about different threads here, which are unpredictable by definition. Depending on the JVM implementation and the running platform’s architecture, the threads can run in any order. In our example specifically, you can see different output variations, because although the threads run concurrently (so when you invoke Thread.start()
a new thread starts running in parallel to your main program), they all have the task to print something to the standard output, and we have no way of knowing which thread will use the output at any given time.
Let’s take a look at two different runs, where we can easily see which thread runs and which Runnable they are using:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | Executing program... Thread 1 with Runnable: MyRunnableImplementation runs...0 Thread 1 with Runnable: MyRunnableImplementation runs...1 Thread 1 with Runnable: MyRunnableImplementation runs...2 Thread 1 with Runnable: MyRunnableImplementation runs...3 Thread 1 with Runnable: MyRunnableImplementation runs...4 Thread 2 with Runnable: MyRunnableImplementation runs...0 Thread 2 with Runnable: MyRunnableImplementation runs...1 Thread 2 with Runnable: MyRunnableImplementation runs...2 Thread 2 with Runnable: MyRunnableImplementation runs...3 Thread 2 with Runnable: MyRunnableImplementation runs...4 Thread 3 with Runnable: Inner class Runnable runs...0 Thread 3 with Runnable: Inner class Runnable runs...1 Thread 3 with Runnable: Inner class Runnable runs...2 Thread 3 with Runnable: Inner class Runnable runs...3 Thread 3 with Runnable: Inner class Runnable runs...4 |
Pretty standard, the output is what someone would possibly expect. Take notice that the two first threads used the same instance of MyRunnableImplementation with no issues, while the third one used the inner class. However, after running it again for a couple of times, we got this output:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | Executing program... Thread 1 with Runnable: MyRunnableImplementation runs...0 Thread 1 with Runnable: MyRunnableImplementation runs...1 Thread 1 with Runnable: MyRunnableImplementation runs...2 Thread 1 with Runnable: MyRunnableImplementation runs...3 Thread 1 with Runnable: MyRunnableImplementation runs...4 Thread 3 with Runnable: Inner class Runnable runs...0 Thread 3 with Runnable: Inner class Runnable runs...1 Thread 3 with Runnable: Inner class Runnable runs...2 Thread 2 with Runnable: MyRunnableImplementation runs...0 Thread 2 with Runnable: MyRunnableImplementation runs...1 Thread 3 with Runnable: Inner class Runnable runs...3 Thread 3 with Runnable: Inner class Runnable runs...4 Thread 2 with Runnable: MyRunnableImplementation runs...2 Thread 2 with Runnable: MyRunnableImplementation runs...3 Thread 2 with Runnable: MyRunnableImplementation runs...4 |
Pretty cool, right? Well, yes, but threads can sometimes cause a real headache, and in many cases, you need to know in which order they run. Luckily, Java contains ways of achieving synchronization and scheduling, which are out of the scope of this tutorial.
4. Download the source code
In this example, we learned the Runnable interface in Java, and how it can be used in association with the Thread
class to create and execute new threads in your program.
This was an example of the Runnable interface in Java.
Download the Eclipse project of this tutorial here: Java Runnable Example
Last updated on Apr. 28th, 2020
The programs in site are very diificult to understand.
I think the output is a bit misleading. It’s possible to have output like this, if we only look at thread1 and thread2:
Thread 2 with Runnable: MyRunnableImplementation runs…0
Thread 2 with Runnable: MyRunnableImplementation runs…1
Thread 2 with Runnable: MyRunnableImplementation runs…2
Thread 2 with Runnable: MyRunnableImplementation runs…3
Thread 1 with Runnable: MyRunnableImplementation runs…0
Thread 2 with Runnable: MyRunnableImplementation runs…4
Thread 1 with Runnable: MyRunnableImplementation runs…1
Thread 1 with Runnable: MyRunnableImplementation runs…2
Thread 1 with Runnable: MyRunnableImplementation runs…3
Thread 1 with Runnable: MyRunnableImplementation runs…4
The order is not guaranteed. T2 is NOT ran after T1. All three threads in the example can have order scrambled.
Also, ease-of-unit-testing, is another reason for the Runnable approach.