Creating Java Threads by Extending Thread Class and by Implementing Runnable Interface
In this post, I will cover creating Java Threads using the two mechanisms provided in Java, that is, by extending the Thread class and by implementing Runnable interface for concurrent programming.
In Java, whenever we discuss concurrent programming we are primarily concerned with threads. However, you should be aware that concurrent programming, in general, deals with both processes and threads. Modern computers nowadays have multi-core CPUs and operating systems that efficiently multitask. What that means is that they support a large multitude of processes all running simultaneously (or what appears to be running simultaneously). As you can see from the process view I have provided below, I have a number of processes running on my PC and each process is multithreaded. However, we should point out that multitasking and concurrency would still be possible even on computers with single-core, single-processor CPU.
Difference between Processes and Threads
Process
A process is an instance of a computer program in execution and may contain many threads. A process contains it’s own memory space that is divided into several distinct sections:
- Text Section – This is primarily your compiled program code or bytecode (in Java-speak)
- Data Section – Where variables are stored, allocated and initialized
- Heap Section – Used to dynamic memory allocation
- Stack Section – Used for local variable storage and method call order
The above sections are a simple representation of a standard memory model. For java specific representation, a good reference I found was Java Memory Model documentation.
Thread
A thread, on the other hand, is sometimes called a lightweight process. Spawning multiple threads within a process is a less expensive operation both in terms of resources and CPU utilization. Since they run inside processes, they share process code and resources such as memory space, process variables and file handles. A Java Thread is an independent path of execution through a program and can access any object within the process so care should be taken when these resources are accessed. One can think of each thread as running in its own context; each thread appears to have its own CPU, with data, memory and its own code. The Java Virtual Machine support multiple threads running concurrently within the same process. Programs that run more than one task at any time are said to be multithreaded.
Thread Characteristics
- Called lightweight processes
- A process may spawn many threads
- Share code and resources such as memory space, process variables and file handles
- Threads maintain their own program counter, Stack and local variables
- Resource overhead of inter-thread communication is low compared to inter-process communications (IPC)
Different ways to create threads
The two general ways to create threads in Java is by:
- Implementing Runnable Interface (java.lang.Runnable)
- Extending Thread Class (java.lang.Thread)
Implementing Runnable Interface
public class MyRunnableThread implements Runnable { @Override public void run() { } }
The Runnable interface only requires one method to be implemented and overridden, the run() method.
- Create your class and ensure that it implements Runnable
- Ensure that your class provides a run() method with the logic that will be used while thread is running
- Create a new Thread and ensure you pass this runnable class to the Thread’s constructor. In my example, I pass in the optional thread name
- At this point, the thread is in “New” state
- Call the start() method on the newly created thread
- Once start() is called, the thread is said to be in the “Ready-To-Run” or “runnable” state.
- A runnable thread may not be yet be running. It will be up your OS scheduler to provide a time slice for your thread to run
- Once the code inside your thread begins executing, the thread is said to in the “Running” state.
For more, information on the various the thread states, please refer to my earlier post on Java Thread States – Lifecycle of Java Threads.
Which is Best — Subclassing Thread or Implementing Runnable?
While both methods will get the job done in most cases. Personally, I prefer implementing Runnable as it gives you the added flexibility of extending some other super class especially if you are trying to adhere to Object Oriented Programming standards using the “IS-A” terminology. That is, your class may really be related to something other than a thread and extending Thread class really doesn’t make much sense. Just be aware that you will need to instantiate the runnable class and hand it over to an instance of Thread during the thread’s construction as we did in our example.
Thread t1= new Thread(new MyRunnableThread(), "Runnable_1");
MyRunnableThread.java
package com.avaldes.tutorials; public class MyRunnableThread implements Runnable { private int counter = 0; public synchronized void increment() { counter++; } @Override public void run() { while (counter < 10) { System.out.format("%s, counter at %d\n", Thread.currentThread().getName(), counter); increment(); } } }
Extending Thread Class
public class MyThread extends Thread { @Override public void run() { } }
For this example, we will create a class called MyThread which extends Thread. We will also do the following:
- Create your class and ensure that it extends Thread
- Ensure that your class provides a run() method which we will override, with the logic that will be used while thread is running
- Create a new MyThread instance and pass in the optional thread name in the constructor
- At this point, the thread is in “New” state
- Call the inherited start() method on the newly created MyThread class
- Once start() is called, the thread is said to be in the “Ready-To-Run” or “runnable” state.
- A runnable thread may not be yet be running. It will be up your OS scheduler to provide a time slice for your thread to run
- Once the code inside your thread begins executing, the thread is said to in the “Running” state.
Please review the code provided below for a better understanding of what I did.
Note
You will notice that in my example I also set the thread Priority by using the setPriority() method call. I will discuss thread priorities in an upcoming post. For now, I just wanted to point that out.
MyRunnableThread.java
package com.avaldes.tutorials; public class MyThread extends Thread { private int counter = 0; MyThread(String name) { super(name); System.out.println("Creating Thread: " + name); } public synchronized void increment() { counter++; } @Override public void run() { while (counter < 10) { System.out.format("%s, counter at %d\n", currentThread().getName(), counter); increment(); } } }
BasicThreadExamples.java
package com.avaldes.tutorials; public class BasicThreadExamples { public static void runnableTests() { Thread t1 = new Thread(new MyRunnableThread(), "Runnable_1"); Thread t2 = new Thread(new MyRunnableThread(), "Runnable_2"); Thread t3 = new Thread(new MyRunnableThread(), "Runnable_3"); t1.setPriority(6); t3.setPriority(9); t1.start(); t2.start(); t3.start(); } public static void threadTests() { MyThread t1 = new MyThread("Thread_1"); MyThread t2 = new MyThread("Thread_2"); MyThread t3 = new MyThread("Thread_3"); t1.setPriority(6); t3.setPriority(9); t1.start(); t2.start(); t3.start(); } public static void main(String[] args) { runnableTests(); threadTests(); } }
Output
Runnable_3, counter at 0 Runnable_1, counter at 0 Runnable_1, counter at 1 Runnable_1, counter at 2 Creating Thread: Thread_1 Runnable_2, counter at 0 Creating Thread: Thread_2 Runnable_1, counter at 3 Runnable_3, counter at 1 Runnable_1, counter at 4 Creating Thread: Thread_3 Runnable_2, counter at 1 Runnable_2, counter at 2 Runnable_2, counter at 3 Runnable_1, counter at 5 Runnable_3, counter at 2 Runnable_1, counter at 6 Thread_3, counter at 0 Thread_2, counter at 0 Runnable_2, counter at 4 Thread_1, counter at 0 Runnable_2, counter at 5 Runnable_2, counter at 6 Thread_2, counter at 1 Thread_3, counter at 1 Runnable_1, counter at 7 Runnable_3, counter at 3 Runnable_1, counter at 8 Thread_3, counter at 2 Thread_2, counter at 2 Runnable_2, counter at 7 Runnable_2, counter at 8 Thread_1, counter at 1 Runnable_2, counter at 9 Thread_2, counter at 3 Thread_3, counter at 3 Runnable_1, counter at 9 Runnable_3, counter at 4 Thread_3, counter at 4 Thread_2, counter at 4 Thread_1, counter at 2 Thread_2, counter at 5 Thread_2, counter at 6 Thread_2, counter at 7 Thread_3, counter at 5 Runnable_3, counter at 5 Thread_3, counter at 6 Thread_2, counter at 8 Thread_1, counter at 3 Thread_2, counter at 9 Thread_3, counter at 7 Runnable_3, counter at 6 Thread_3, counter at 8 Thread_1, counter at 4 Thread_3, counter at 9 Runnable_3, counter at 7 Thread_1, counter at 5 Runnable_3, counter at 8 Thread_1, counter at 6 Runnable_3, counter at 9 Thread_1, counter at 7 Thread_1, counter at 8 Thread_1, counter at 9
Related Posts
- Java Thread, Concurrency and Multithreading Tutorial
This Java Thread tutorial will give you a basic overview on Java Threads and introduce the entire tutorial series on concurrency and multithreading. From here, you will learn about many java thread concepts like: Thread States, Thread Priority, Thread Join, and ThreadGroups. In addition, you will learn about using the volatile keyword and examples on using wait, notify and notifyAll. - Java Thread States - Life Cycle of Java Threads
Get a basic understanding of the various thread states. Using the state transition diagram we show the various states for a Java thread and the events that cause the thread to jump from one state to another. - Creating Java Threads Example
In this post we cover creating Java Threads using the two mechanisms provided in Java, that is, by extending the Thread class and by implementing Runnable interface for concurrent programming. - Java Thread Priority Example
In this post we cover Thread priorities in Java. By default, a java thread inherits the priority (implicit) of its parent thread. Using the setPriority() method you can increase or decrease the thread priority of any java thread. - Java ThreadGroup Example
Sometimes we will need to organize and group our threads into logical groupings to aid in thread management. By placing threads in a threadGroup all threads in that group can be assigned properties as a set, instead of going through the tedious task of assigning properties individually. - Java Thread Sleep Example
We seem to use this method very often to temporarily suspend the current threads execution for a specific period of time. Let's spend some time and familiarize ourselves with what this method actually does. - Java Thread Join Example
In Java, using Thread.join() causes the current thread to wait until the specified thread dies. Using this method allows us to impose an order such that we can make one thread wait until the other completes doing what it needed to do, such as completing a calculation. - Examining Volatile Keyword with Java Threads
When we declare a field as volatile, the JVM will guarantee visibility, atomicity and ordering of the variable. Without it the data may be cached locally in CPU cache and as a result changes to the variable by another thread may not be seen by all other threads resulting in inconsistent behaviour. - Java Threads Wait, Notify and NotifyAll Example
The purpose of using notify() and notifyAll() is to enable threads to communicate with one another via some object on which to performing the locking. A thread using the wait() method must own a lock on the object. Once wait() is called, the thread releases the lock, and waits for another thread to either call notify() or notifyAll() method. - Java Thread Deadlock Example and Thread Dump Analysis using VisualVM
Deadlock is a condition where several threads are blocking forever, waiting for the other to finish but they never do. This tutorial will discuss situations that will lead to Java Thread deadlock conditions and how they can be avoided. In addition, we will discuss using Java VisualVM to pinpoint and analyze the source of the deadlock conditions. - Java Thread Starvation and Livelock with Examples
Starvation occurs when a thread is continually denied access to resources and as a result it is unable to make progress. Thread liveLock is a condition that closely resembles deadlock in that several processes are blocking each other. But with livelock, a thread is unable to make any progress because every time it tries the operation always fails. - Java Synchronization and Thread Safety Tutorial with Examples
One of Java's many strengths come from the fact that it supports multithreading by default as has so from the very onset. One of the mechanisms that Java uses for this is via synchronization. When we use the synchronized keyword in Java we are trying limit the number of threads that can simultaneously access and modify a shared resource. The mechanism that is used in Java's synchronization is called a monitor. - Creating a Thread Safe Singleton Class with Examples
In this tutorial we cover many examples of creating thread-safe singleton classes and discuss some of the shortfalls of each and provide some recommendations on best approaches for a fast, efficient and highly concurrent solution. - Java Threads and Concurrent Locks with Examples
In this tutorial we will focus primarily on using the concurrent utilities and how these can make concurrent programming easier for us.
Leave a Reply