The Runnable
InterfaceS2C Home « The Runnable
Interface
In the last lesson we saw how to run parts of a program concurrently by subclassing the Thread
class. The second way of running parts of a program concurrently is by declaring a class that
implements the Runnable
interface and is the subject of this lesson.
We saw various examples of thread usage and we we also looked at some of the methods that are available within the Thread
class in the last lesson. The Java API offers us an alternative to
subclassing the Thread
class, which offers us certain advantages when used. When we subclass the Thread
class our threads have to inherit from Thread
and
therefore we are not only limited to that classes functionality but can't extend anything else. Fortunately for us we can also execute independent threads by implementing the Runnable
interface which declares a single run()
method that gets executed when the thread is started. Using this approach we are free to extend another class if we need to for added functionality.
This is possible because several of the Thread
classes overloaded constructors accept a Runnable
object as a parameter. So as long as we implement this interface and use our
implementing class in the threads construction, then the thread knows to use the implementing classes overridden run()
method when the thread is started.
Thread
Methods OverviewTop
The table below shows the declarations of the methods of the Thread
class used in this lesson:
Method Declaration | Description |
---|---|
public static Thread currentThread() | Returns a reference to the currently executing thread object. |
public final boolean isDaemon() | Test if this is a daemon thread. |
public final String getName() | Obtains and returns the name of the thread. |
public final void join() | Waits for current thread to die. |
public void run() | If this thread was constructed using a subclass of the Thread class this method does nothing and should be overridden in the subclass.If this thread was constructed using a separate Runnable run object, then that Runnable object's run() method is called. |
public final void setDaemon(boolean on) | Marks this thread as a daemon thread if on set to true , or a user thread when on set to false . |
public void start() | The JVM calls the run() method of this thread, so it can begin execution. |
We will go through the methods mentioned in much greater detail as we go through this lesson. Use the links in the table above to go to the code example where the method is first used.
Creating A Single ThreadTop
To see how we can use threads via the Runnable
interface we will recreate the first two examples of thread subclassing from the last lesson. We will keep it simple to begin with, so
lets start by creating a single thread using the Runnable
interface:
/*
Create a single thread
*/
public class TestRunnableSingleThread implements Runnable {
// Override run() method of Runnable interface to execute a new thread
public void run() {
// Get current active thread
Thread activeThread = Thread.currentThread();
System.out.println("The thread named: " + activeThread.getName() + " is starting.");
System.out.println("Is this a daemon thread? " + activeThread.isDaemon());
System.out.println("The thread named: " + activeThread.getName() + " is ending.");
}
public static void main(String[] args) {
System.out.println("Main user thread has started.");
// Create a new thread passing across a Runnable object of this class
Thread th = new Thread(new TestRunnableSingleThread(), "Thread1");
// Power up the thread via the start() method
th.start();
System.out.println("Main user thread has ended.");
}
}
Save, compile and run the TestRunnableSingleThread
class in directory c:\_Concurrency in the usual way.
The first thing we do in the TestRunnableSingleThread
class is to implement the Runnable
interface. We override the run()
method from the Runnable
interface. In our main()
method, we use our implementing class in the construction of a Thread
object of TestRunnableSingleThread
class, so the thread knows to use the
implementing classes overridden run()
method when the thread is started. We then call the start()
method on this object, which causes our overriden run()
method to be invoked. Our override of the run()
method uses the static currentThread()
method of the Thread
class to get a reference to the active thread.
We use the reference to get various information about the thread which we use to outputs a few messages showing the thread name and a test to see if this is a daemon thread.
Creating Multiple ThreadsTop
Ok, we have seen how to create a single thread using the Runnable
interface. It is now time to look at creating multiple threads within a program using the Runnable
interface:
/*
Create multiple threads
*/
public class TestRunnableMutipleThread implements Runnable {
// Override run() method of Runnable interface to execute a new thread
public void run() {
// Get current active thread
Thread activeThread = Thread.currentThread();
System.out.println("The thread named: " + activeThread.getName() + " is starting.");
System.out.println(activeThread.getName() + " a daemon thread? " + activeThread.isDaemon());
System.out.println("The thread named: " + activeThread.getName() + " is ending.");
}
public static void main(String[] args) {
System.out.println("Main user thread has started.");
// Create a new thread
Thread th1 = new Thread(new TestRunnableMutipleThread(), "Thread1");
Thread th2 = new Thread(new TestRunnableMutipleThread(), "Thread2");
Thread th3 = new Thread(new TestRunnableMutipleThread(), "Thread3");
// Power up the threads via the start() method
th1.start();
th2.setDaemon(true);
th2.start();
th3.start();
System.out.println("Main user thread has ended.");
}
}
Save, compile and run the TestRunnableMutipleThread
class in directory c:\_Concurrency in the usual way.
As with all the examples in this section where we use multiple threads, the output you get may vary from our screenshots as we have limited control over the order in which the threads are run.
The first thing we do in the TestRunnableMutipleThread
class is to implement the Runnable
interface. We override the run()
method from the Runnable
interface. In our main()
method, we use our implementing class in the construction of three Thread
objects of TestRunnableMutipleThread
class, so the thread knows to
use the implementing classes overridden run()
method when the threads are started. We then call the start()
method on these object, which causes our overriden
run()
method to be invoked. Our override of the run()
method uses the static currentThread()
method of the Thread
class to get a reference to the active
thread. We use the reference to get various information about the thread which we use to outputs a few messages showing the thread name and a test to see if this is a daemon thread.
Connecting ThreadsTop
We have mentioned several times that we have limited control over the order in which the threads are run, but we do have some control. As we showed in the previous lesson, we can cease execution of a thread
for a specified amount of time using the sleep()
method. We can also use the yield()
method, to cease execution of a thread up to a specified amount of time,and there are also
options to prioritize and lock threads, all of which we will look at in later lessons of this section.
The join()
MethodTop
There is another option available to us, the join()
method of the Thread
class which we will take a closer look at now. The join()
method allows us to connect the current
thread to a named thread, which is very handy when we want to guarantee that one thread finishes before another. The code below shows an example of using the join()
method:
/*
Connecting threads using the join() method
*/
public class TestConnectThread implements Runnable {
// Override run() method of Runnable interface to execute a new thread
public void run() {
// Get current active thread
Thread activeThread = Thread.currentThread();
System.out.println("The thread named: " + activeThread.getName() + " is starting.");
System.out.println(activeThread.getName() + " a daemon thread? " + activeThread.isDaemon());
System.out.println("The thread named: " + activeThread.getName() + " is ending.");
}
public static void main(String[] args) {
System.out.println("Main user thread: " + Thread.currentThread().getName() + " has started.");
// Create a new thread
Thread th1 = new Thread(new TestConnectThread(), "Thread1");
Thread th2 = new Thread(new TestConnectThread(), "Thread2");
Thread th3 = new Thread(new TestConnectThread(), "Thread3");
// Power up the threads via the start() method
th1.start();
// join() main thread to 'th1' so if finishes after 'th1' dies
try {
th1.join();
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + ": " + ex);
}
th2.setDaemon(true);
th2.start();
th3.start();
System.out.println("Main user thread: " + Thread.currentThread().getName() + " has ended.");
}
}
Save, compile and run the TestConnectThread
class in directory c:\_Concurrency in the usual way.
The first thing we do in the TestConnectThread
class is to implement the Runnable
interface. We override the run()
method from the Runnable
interface. In our main()
method, we use our implementing class in the construction of three Thread
objects of TestRunnableMutipleThread
class, so the thread knows to
use the implementing classes overridden run()
method when the threads are started. We then call the start()
method on 'th1' and use the join()
method on the
currently executing thread. We are in the main()
method so the active thread is the user thread that was kicked off when we started the JVM, so is the thread named
'main'.
In essence what the join()
method is doing is moving the thread called 'main' to a blocked state, in which it will remain until the 'th1' thread dies. If we were to use the
join()
method in the overridden run()
method then the current thread could be any of the new threads created if they have been started.
We then call the start()
method on the other two threads we created. Our override of the run()
method uses the static currentThread()
method of the
Thread
class to get a reference to the active thread. We use the reference to get various information about the thread which we use to output a few messages showing the thread
name and a test to see if this is a daemon thread. As you can see from the output the 'th1' (thread1) thread completes before the main thread does. This will always be the case whatever
order the threads start the run()
method in, because of the connection we made.
Lesson 2 Complete
In this lesson we looked at the second way of running parts of a program concurrently by declaring a class that implements the Runnable interface.
What's Next?
In the next lesson we look at synchronization and how we can control access to our code at the method or block level.