Java Thread Class
Last modified: April 13, 2025
The java.lang.Thread
class is fundamental to Java's multithreading
capabilities. It represents a thread of execution in a Java program. Threads
allow concurrent execution of code segments, enabling efficient resource
utilization.
Threads share the same memory space but execute independently. The Thread class provides methods to create, control, and manage threads. Understanding threads is essential for writing responsive and efficient Java applications.
Thread Class Methods
The Thread class provides methods to control thread execution and query thread
status. Key methods include start
, run
,
sleep
, join
, and interrupt
. These
methods manage the thread lifecycle and synchronization.
public class Thread implements Runnable { public Thread() {...} public Thread(Runnable target) {...} public void start() {...} public void run() {...} public static void sleep(long millis) throws InterruptedException {...} public final void join() throws InterruptedException {...} public void interrupt() {...} public static Thread currentThread() {...} public final boolean isAlive() {...} public final void setPriority(int priority) {...} }
The code above shows key methods of the Thread class. These methods enable thread creation, execution control, and status monitoring. Threads can be created by extending Thread or implementing Runnable.
Creating Thread by Extending Thread Class
The simplest way to create a thread is by extending the Thread class and
overriding its run
method. The start
method begins
thread execution. This approach is straightforward but limits inheritance.
package com.zetcode; class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println("Thread running: " + i); try { Thread.sleep(500); // Pause for 500ms } catch (InterruptedException e) { System.out.println("Thread interrupted"); return; } } } } void main() { MyThread thread = new MyThread(); thread.start(); // Start the thread // Main thread continues execution for (int i = 0; i < 3; i++) { System.out.println("Main thread: " + i); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } }
This example demonstrates thread creation by extending Thread. The main thread and MyThread execute concurrently. The output shows interleaved execution. Thread.sleep pauses execution without consuming CPU resources.
Creating Thread by Implementing Runnable
A more flexible approach implements the Runnable interface. This allows the class to extend another class while still being executable as a thread. The Runnable object is passed to a Thread constructor.
package com.zetcode; class Task implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println("Task executing: " + i); try { Thread.sleep(400); } catch (InterruptedException e) { System.out.println("Task interrupted"); return; } } } } void main() { Task task = new Task(); Thread thread = new Thread(task); thread.start(); // Main thread work for (int i = 0; i < 4; i++) { System.out.println("Main thread working"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } }
This example shows thread creation using Runnable. The Task class implements Runnable and defines work in its run method. A Thread object is created with the Task instance. Both approaches achieve similar results but Runnable is more flexible.
Thread Sleep and Interruption
The sleep
method pauses thread execution for a specified time.
Threads can be interrupted using interrupt
, which sends an
interruption signal. Proper interruption handling makes threads more responsive.
package com.zetcode; class Worker implements Runnable { @Override public void run() { try { for (int i = 0; i < 10; i++) { System.out.println("Working... " + i); if (Thread.interrupted()) { System.out.println("Thread was interrupted"); return; } Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Thread interrupted during sleep"); return; } } } void main() throws InterruptedException { Thread worker = new Thread(new Worker()); worker.start(); Thread.sleep(2000); // Let worker run for 2 seconds worker.interrupt(); // Interrupt the worker worker.join(); // Wait for worker to finish System.out.println("Main thread done"); }
This example demonstrates thread interruption. The Worker checks for interruption
using Thread.interrupted
and handles InterruptedException.
The main thread interrupts Worker after 2 seconds. Proper interruption handling
ensures clean thread termination.
Thread Joining
The join
method allows one thread to wait for another to complete.
This is useful when thread execution order matters or when results need to be
combined. Join can specify a maximum wait time.
package com.zetcode; class Calculator implements Runnable { private int result; @Override public void run() { result = 0; for (int i = 1; i <= 100; i++) { result += i; try { Thread.sleep(10); } catch (InterruptedException e) { System.out.println("Calculation interrupted"); return; } } } public int getResult() { return result; } } void main() throws InterruptedException { Calculator calc = new Calculator(); Thread calcThread = new Thread(calc); calcThread.start(); System.out.println("Waiting for calculation to complete..."); calcThread.join(); // Wait for calculation to finish System.out.println("Result: " + calc.getResult()); }
This example shows thread joining. The main thread waits for Calculator to
complete using join
. Without joining, main might access the
result before calculation finishes. Joining ensures proper synchronization.
Thread Priority
Thread priority hints to the scheduler about thread importance. Priorities range from 1 (MIN_PRIORITY) to 10 (MAX_PRIORITY). The default is 5 (NORM_PRIORITY). Higher priority threads get more CPU time but aren't guaranteed to run first.
package com.zetcode; class Counter implements Runnable { private String name; public Counter(String name) { this.name = name; } @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + ": " + i); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } } void main() { Thread lowPriority = new Thread(new Counter("Low")); Thread highPriority = new Thread(new Counter("High")); lowPriority.setPriority(Thread.MIN_PRIORITY); highPriority.setPriority(Thread.MAX_PRIORITY); highPriority.start(); lowPriority.start(); }
This example demonstrates thread priorities. The high priority thread often executes before the low priority one, but this isn't guaranteed. Thread scheduling depends on the JVM and operating system implementation.
Thread Synchronization
Thread synchronization prevents concurrent access to shared resources. The
synchronized
keyword creates critical sections that only one
thread can enter at a time. This prevents race conditions and data corruption.
package com.zetcode; class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } class Incrementer implements Runnable { private Counter counter; public Incrementer(Counter counter) { this.counter = counter; } @Override public void run() { for (int i = 0; i < 10000; i++) { counter.increment(); } } } void main() throws InterruptedException { Counter counter = new Counter(); Thread t1 = new Thread(new Incrementer(counter)); Thread t2 = new Thread(new Incrementer(counter)); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("Final count: " + counter.getCount()); }
This example shows thread synchronization. Without synchronized methods, the final count might be less than 20000 due to race conditions. Synchronization ensures atomic access to the count variable. The result is always 20000.
Source
Java Thread Class Documentation
This tutorial covered essential Thread class concepts with practical examples. Understanding threads is crucial for writing concurrent Java applications. Proper thread management ensures efficient resource utilization and responsiveness.
Author
List all Java tutorials.