In this post, we implement a basic Multithreading example in Java. Multithreading allows multiple threads to execute concurrently within a single program, enabling tasks to run in parallel rather than one after another. Java has built-in support for multithreading through the Thread class and the Runnable interface.
What is Multithreading?
A thread is the smallest unit of execution within a process. When a program creates multiple threads, the operating system’s thread scheduler interleaves their execution — giving each thread a slice of CPU time in turn. This makes it appear as though they are running simultaneously (and on multi-core systems, they actually can be).
In this example, we create two threads by extending the Thread class and overriding its run() method. Each thread prints a label 4 times, pausing 500 ms between prints. Both threads run concurrently, so their output interleaves.
start()— Tells the JVM to create a new OS-level thread and invokerun()on it. Callingrun()directly would execute it on the current thread, not a new one.Thread.sleep(ms)— Pauses the current thread for the given number of milliseconds, allowing other threads to execute.InterruptedException— Must be caught when callingsleep(). It fires if another thread interrupts this one while it is sleeping.
Java Code Implementation
// ============================================================
// Multithreading Example in Java
// Demonstrates concurrent execution of two threads
// Each thread prints a label 4 times with a 500ms pause
// ============================================================
// Custom thread class — extends the built-in Thread class
class LabelPrinterThread extends Thread {
private String threadLabel; // The text this thread will print on each iteration
// Constructor: assigns the display label to this thread instance
LabelPrinterThread(String label) {
this.threadLabel = label;
}
// run() is called automatically by the JVM when start() is invoked.
// This method contains all the work this thread will perform.
@Override
public void run() {
for (int count = 0; count < 4; count++) { // Print label exactly 4 times
System.out.println(" " + threadLabel);
try {
Thread.sleep(500); // Pause 500 ms before next print
} catch (InterruptedException interruptedEx) {
// Handle the case where this thread is interrupted during sleep
System.out.println(threadLabel + " thread was interrupted: "
+ interruptedEx.getMessage());
}
}
}
}
// Main class — entry point of the program
public class MultithreadingDemo {
public static void main(String[] args) {
// Create two thread instances, each with a different label
LabelPrinterThread thread1 = new LabelPrinterThread("piit");
LabelPrinterThread thread2 = new LabelPrinterThread("new panvel");
// Start both threads — the JVM schedules them for concurrent execution.
// The order of their output is determined by the OS thread scheduler
// and is NOT guaranteed to be strictly alternating.
thread1.start();
thread2.start();
// main() may return here before the threads finish — that is expected.
// The JVM keeps running until all non-daemon threads complete.
}
}
Explanation of the Code
LabelPrinterThread extends Thread— Creates a custom thread type. The fieldthreadLabelstores the string each instance will print. By extendingThread, the class inheritsstart(),sleep(), and other threading infrastructure.- Constructor — Accepts the label string and stores it as an instance variable. Each thread object maintains its own copy of
threadLabel, so the two threads are independent. run()method — The@Overrideannotation confirms we are correctly overridingThread.run(). The loop runs 4 times. Inside,Thread.sleep(500)voluntarily yields CPU time for 500 ms, giving the other thread a chance to run.thread1.start()vsthread1.run()— Callingstart()creates a new OS thread and invokesrun()on it asynchronously. Callingrun()directly would execute it synchronously on the main thread — no concurrency. Always usestart()for true multithreading.
Sample Output
piit
new panvel
piit
new panvel
new panvel
piit
piit
new panvel
Step-by-Step Explanation of Input/Output
This program takes no user input. Both threads are created and started programmatically in main().
- After
thread1.start()andthread2.start(), both threads are alive and competing for CPU time. - Thread 1 prints
"piit"and then sleeps 500 ms. During that sleep, Thread 2 gets the CPU and prints"new panvel", then also sleeps. - This alternating pattern repeats roughly 4 times each.
- The output order is not guaranteed. Sometimes two consecutive lines from the same thread appear (as shown on lines 5–6 where
"new panvel"then"piit"appear back-to-back). This depends on OS scheduling decisions and can vary between runs and machines. - Total output: 4 prints from Thread 1 + 4 prints from Thread 2 = 8 lines.
See Also
Bottom line is…
Extending Thread is the simplest way to create threads in Java, but it has a limitation: since Java supports only single inheritance, your class can’t extend any other class if it already extends Thread. The preferred approach in real-world code is to implement the Runnable interface instead. For production systems, Java’s ExecutorService and java.util.concurrent package provide higher-level thread management with thread pools, futures, and task queuing — far more powerful than managing raw threads manually.