google-site-verification: google61fe8ba583a51912.html
Multithreading with Thread Class in Java

The Thread class is the fundamental way to create and manage threads in Java. It provides methods to create, control, and synchronize threads.

1. Creating Threads by Extending Thread Class

Basic Thread Creation

public class BasicThreadCreation { // Method 1: Extending Thread class static class MyThread extends Thread { private String threadName; public MyThread(String name) { this.threadName = name; } @Override public void run() { System.out.println(threadName + " is running..."); // Simulate some work for (int i = 1; i <= 5; i++) { System.out.println(threadName + " - Count: " + i); try { Thread.sleep(1000); // Pause for 1 second } catch (InterruptedException e) { System.out.println(threadName + " was interrupted!"); return; } } System.out.println(threadName + " finished execution."); } } public static void main(String[] args) { System.out.println("=== Basic Thread Creation by Extending Thread Class ==="); System.out.println("Main thread started: " + Thread.currentThread().getName()); // Create thread instances MyThread thread1 = new MyThread("Thread-1"); MyThread thread2 = new MyThread("Thread-2"); MyThread thread3 = new MyThread("Thread-3"); // Start the threads thread1.start(); thread2.start(); thread3.start(); // Main thread continues execution System.out.println("Main thread is doing other work..."); // Wait for all threads to complete try { thread1.join(); thread2.join(); thread3.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("All threads completed. Main thread finishing."); } }

Thread with Custom Properties

public class ThreadWithProperties { static class WorkerThread extends Thread { private int taskCount; private long delay; public WorkerThread(String name, int taskCount, long delay) { super(name); // Set thread name this.taskCount = taskCount; this.delay = delay; this.setPriority(Thread.NORM_PRIORITY); // Set thread priority } @Override public void run() { System.out.println(getName() + " started with priority: " + getPriority()); System.out.println(getName() + " is " + (isDaemon() ? "daemon" : "user") + " thread"); for (int i = 1; i <= taskCount; i++) { System.out.println(getName() + " - Task " + i + "/" + taskCount); try { Thread.sleep(delay); } catch (InterruptedException e) { System.out.println(getName() + " was interrupted during task " + i); return; } // Check if thread is interrupted if (Thread.interrupted()) { System.out.println(getName() + " received interrupt signal"); return; } } System.out.println(getName() + " completed all tasks."); } } public static void main(String[] args) { System.out.println("=== Thread with Custom Properties ==="); // Create threads with different properties WorkerThread normalThread = new WorkerThread("Normal-Worker", 5, 1000); WorkerThread fastThread = new WorkerThread("Fast-Worker", 8, 500); // Set thread priorities normalThread.setPriority(Thread.MIN_PRIORITY); // Priority 1 fastThread.setPriority(Thread.MAX_PRIORITY); // Priority 10 // Create a daemon thread WorkerThread daemonThread = new WorkerThread("Daemon-Worker", 10, 300); daemonThread.setDaemon(true); // This thread will terminate when main thread ends System.out.println("Main thread priority: " + Thread.currentThread().getPriority()); // Start all threads normalThread.start(); fastThread.start(); daemonThread.start(); // Demonstrate thread states demonstrateThreadStates(normalThread, fastThread, daemonThread); // Wait for non-daemon threads to complete try { normalThread.join(); fastThread.join(); // Don't join daemon thread - it will terminate when main ends } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main thread completed."); } public static void demonstrateThreadStates(Thread... threads) { System.out.println("\n=== Thread States ==="); for (Thread thread : threads) { System.out.println(thread.getName() + " state: " + thread.getState()); } // Check states after a short delay try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("\n=== Thread States After 100ms ==="); for (Thread thread : threads) { System.out.println(thread.getName() + " state: " + thread.getState()); } } }

2. Thread Lifecycle and States

Understanding Thread States

public class ThreadLifecycle { static class StateMonitoringThread extends Thread { private Thread targetThread; public StateMonitoringThread(Thread targetThread) { super("State-Monitor"); this.targetThread = targetThread; this.setDaemon(true); } @Override public void run() { while (targetThread.isAlive()) { Thread.State state = targetThread.getState(); System.out.println("[" + new java.util.Date() + "] " + targetThread.getName() + " state: " + state); try { Thread.sleep(200); } catch (InterruptedException e) { break; } } System.out.println(targetThread.getName() + " is no longer alive."); } } static class WorkThread extends Thread { private int workDuration; public WorkThread(String name, int workDuration) { super(name); this.workDuration = workDuration; } @Override public void run() { System.out.println(getName() + " - Starting work for " + workDuration + "ms"); // NEW -> RUNNABLE System.out.println(getName() + " - State after start: " + getState()); // Simulate work with TIMED_WAITING state for (int i = 1; i <= 3; i++) { System.out.println(getName() + " - Working phase " + i); try { // Thread goes to TIMED_WAITING state Thread.sleep(workDuration / 3); } catch (InterruptedException e) { System.out.println(getName() + " - Interrupted during work"); return; } } // Simulate BLOCKED state synchronized (ThreadLifecycle.class) { System.out.println(getName() + " - Entered synchronized block"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + " - Work completed"); } } public static void main(String[] args) throws InterruptedException { System.out.println("=== Thread Lifecycle and States ==="); WorkThread worker1 = new WorkThread("Worker-1", 1500); WorkThread worker2 = new WorkThread("Worker-2", 1200); // Start monitoring before starting workers StateMonitoringThread monitor1 = new StateMonitoringThread(worker1); StateMonitoringThread monitor2 = new StateMonitoringThread(worker2); monitor1.start(); monitor2.start(); System.out.println("Worker-1 state before start: " + worker1.getState()); // NEW // Start first worker worker1.start(); Thread.sleep(100); // Small delay to see state change System.out.println("Worker-1 state after start: " + worker1.getState()); // RUNNABLE/TIMED_WAITING // Start second worker worker2.start(); // Demonstrate WAITING state demonstrateWaitingState(); // Wait for workers to complete worker1.join(); worker2.join(); System.out.println("Worker-1 final state: " + worker1.getState()); // TERMINATED System.out.println("Worker-2 final state: " + worker2.getState()); // TERMINATED System.out.println("\nMain thread completed."); } public static void demonstrateWaitingState() throws InterruptedException { System.out.println("\n=== Demonstrating WAITING State ==="); Object lock = new Object(); Thread waitingThread = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " - Going to wait state"); lock.wait(); // WAITING state System.out.println(Thread.currentThread().getName() + " - Resumed from wait"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "Waiting-Thread"); Thread notifyingThread = new Thread(() -> { try { Thread.sleep(1000); // Let waiting thread enter wait state synchronized (lock) { System.out.println(Thread.currentThread().getName() + " - Notifying waiting thread"); lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } }, "Notifying-Thread"); waitingThread.start(); notifyingThread.start(); // Monitor the waiting thread state Thread.sleep(500); System.out.println("Waiting-Thread state after 500ms: " + waitingThread.getState()); // WAITING waitingThread.join(); notifyingThread.join(); } }

3. Thread Methods and Control

Thread Control Methods

public class ThreadControlMethods { static class ControlledThread extends Thread { private volatile boolean running = true; private int counter = 0; public ControlledThread(String name) { super(name); } public void stopGracefully() { running = false; interrupt(); // Interrupt if sleeping/waiting } @Override public void run() { System.out.println(getName() + " started."); while (running && !isInterrupted()) { counter++; System.out.println(getName() + " - Counter: " + counter); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(getName() + " - Sleep interrupted!"); // Restore interrupt status Thread.currentThread().interrupt(); } // Check if we should yield to other threads if (counter % 3 == 0) { System.out.println(getName() + " - Yielding to other threads"); Thread.yield(); } } System.out.println(getName() + " stopped. Final counter: " + counter); } public int getCounter() { return counter; } } public static void main(String[] args) throws InterruptedException { System.out.println("=== Thread Control Methods ==="); ControlledThread thread1 = new ControlledThread("Controlled-Thread-1"); ControlledThread thread2 = new ControlledThread("Controlled-Thread-2"); // Start threads thread1.start(); thread2.start(); // Let threads run for some time Thread.sleep(5000); System.out.println("\n=== Stopping Threads Gracefully ==="); // Stop thread1 gracefully System.out.println("Stopping " + thread1.getName()); thread1.stopGracefully(); // Let thread2 run a bit longer Thread.sleep(2000); System.out.println("Stopping " + thread2.getName()); thread2.stopGracefully(); // Wait for threads to finish thread1.join(); thread2.join(); System.out.println("\nFinal counters:"); System.out.println(thread1.getName() + ": " + thread1.getCounter()); System.out.println(thread2.getName() + ": " + thread2.getCounter()); demonstrateThreadInterruption(); demonstrateThreadJoinWithTimeout(); } public static void demonstrateThreadInterruption() throws InterruptedException { System.out.println("\n=== Thread Interruption Demo ==="); Thread interruptibleThread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " - Starting work"); while (!Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + " - Working..."); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + " - Interrupted during sleep!"); // Important: When InterruptedException is caught, // interrupt status is cleared. We should re-interrupt. Thread.currentThread().interrupt(); } } System.out.println(Thread.currentThread().getName() + " - Cleanup before exit"); }, "Interruptible-Thread"); interruptibleThread.start(); // Let thread run for 3 seconds Thread.sleep(3000); // Interrupt the thread System.out.println("Main - Interrupting " + interruptibleThread.getName()); interruptibleThread.interrupt(); interruptibleThread.join(); System.out.println("Interruptible thread completed."); } public static void demonstrateThreadJoinWithTimeout() throws InterruptedException { System.out.println("\n=== Thread Join with Timeout ==="); Thread longRunningThread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " - Starting long task"); try { Thread.sleep(5000); // Simulate long task System.out.println(Thread.currentThread().getName() + " - Long task completed"); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + " - Interrupted!"); } }, "Long-Running-Thread"); longRunningThread.start(); // Wait for thread with timeout System.out.println("Main - Waiting for long-running thread with 2 second timeout"); longRunningThread.join(2000); // Wait max 2 seconds if (longRunningThread.isAlive()) { System.out.println("Main - Thread is still alive after timeout, interrupting..."); longRunningThread.interrupt(); } else { System.out.println("Main - Thread completed within timeout"); } longRunningThread.join(); // Wait for final completion } }

4. Thread Synchronization

Synchronized Methods and Blocks

public class ThreadSynchronization { static class SharedResource { private int counter = 0; private final Object lock = new Object(); // Synchronized method public synchronized void increment() { counter++; System.out.println(Thread.currentThread().getName() + " - Counter: " + counter); try { Thread.sleep(100); // Simulate some work } catch (InterruptedException e) { e.printStackTrace(); } } // Synchronized block with custom lock public void decrement() { synchronized (lock) { if (counter > 0) { counter--; System.out.println(Thread.currentThread().getName() + " - Counter: " + counter); } } } public int getCounter() { return counter; } } static class CounterThread extends Thread { private SharedResource resource; private boolean increment; public CounterThread(String name, SharedResource resource, boolean increment) { super(name); this.resource = resource; this.increment = increment; } @Override public void run() { for (int i = 0; i < 5; i++) { if (increment) { resource.increment(); } else { resource.decrement(); } try { Thread.sleep(50); // Small delay between operations } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { System.out.println("=== Thread Synchronization ==="); SharedResource resource = new SharedResource(); // Create multiple threads accessing shared resource CounterThread incrementer1 = new CounterThread("Incrementer-1", resource, true); CounterThread incrementer2 = new CounterThread("Incrementer-2", resource, true); CounterThread decrementer1 = new CounterThread("Decrementer-1", resource, false); incrementer1.start(); incrementer2.start(); decrementer1.start(); // Wait for all threads to complete incrementer1.join(); incrementer2.join(); decrementer1.join(); System.out.println("Final counter value: " + resource.getCounter()); demonstrateProducerConsumer(); } public static void demonstrateProducerConsumer() throws InterruptedException { System.out.println("\n=== Producer-Consumer Problem ==="); class MessageQueue { private String message; private boolean hasMessage = false; public synchronized void put(String message) { while (hasMessage) { try { wait(); // Wait for consumer to consume } catch (InterruptedException e) { e.printStackTrace(); } } this.message = message; hasMessage = true; System.out.println("Produced: " + message); notifyAll(); // Notify waiting consumers } public synchronized String take() { while (!hasMessage) { try { wait(); // Wait for producer to produce } catch (InterruptedException e) { e.printStackTrace(); } } String result = message; hasMessage = false; System.out.println("Consumed: " + result); notifyAll(); // Notify waiting producers return result; } } MessageQueue queue = new MessageQueue(); // Producer thread Thread producer = new Thread(() -> { String[] messages = {"Message 1", "Message 2", "Message 3", "Message 4", "DONE"}; for (String message : messages) { queue.put(message); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }, "Producer"); // Consumer thread Thread consumer = new Thread(() -> { String message; do { message = queue.take(); try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } } while (!"DONE".equals(message)); }, "Consumer"); producer.start(); consumer.start(); producer.join(); consumer.join(); System.out.println("Producer-Consumer demo completed."); } }

5. Real-World Thread Examples

File Processing with Multiple Threads

import java.io.*; import java.util.*; import java.util.concurrent.*; public class FileProcessingThreads { static class FileProcessor extends Thread { private File file; private CountDownLatch latch; private Map<String, Integer> wordCount; public FileProcessor(File file, CountDownLatch latch, Map<String, Integer> wordCount) { super("FileProcessor-" + file.getName()); this.file = file; this.latch = latch; this.wordCount = wordCount; } @Override public void run() { System.out.println(getName() + " - Processing file: " + file.getName()); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; while ((line = reader.readLine()) != null) { String[] words = line.split("\\s+"); for (String word : words) { if (!word.trim().isEmpty()) { synchronized (wordCount) { wordCount.merge(word.toLowerCase(), 1, Integer::sum); } } } } } catch (IOException e) { System.err.println(getName() + " - Error processing file: " + e.getMessage()); } finally { System.out.println(getName() + " - Completed processing: " + file.getName()); latch.countDown(); // Signal completion } } } static class ResultAggregator extends Thread { private CountDownLatch latch; private Map<String, Integer> wordCount; public ResultAggregator(CountDownLatch latch, Map<String, Integer> wordCount) { super("ResultAggregator"); this.latch = latch; this.wordCount = wordCount; } @Override public void run() { try { System.out.println("ResultAggregator - Waiting for all file processors..."); latch.await(); // Wait for all file processors to complete System.out.println("\n=== Word Count Results ==="); // Display top 10 most frequent words wordCount.entrySet().stream() .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) .limit(10) .forEach(entry -> System.out.printf("%-15s: %d%n", entry.getKey(), entry.getValue())); System.out.println("Total unique words: " + wordCount.size()); } catch (InterruptedException e) { System.err.println("ResultAggregator - Interrupted while waiting"); } } } public static void main(String[] args) throws InterruptedException { System.out.println("=== File Processing with Multiple Threads ==="); // Create sample text files for demonstration createSampleFiles(); File directory = new File("sample_files"); File[] files = directory.listFiles((dir, name) -> name.endsWith(".txt")); if (files == null || files.length == 0) { System.out.println("No text files found in sample_files directory"); return; } Map<String, Integer> wordCount = new ConcurrentHashMap<>(); CountDownLatch latch = new CountDownLatch(files.length); // Start file processor threads List<FileProcessor> processors = new ArrayList<>(); for (File file : files) { FileProcessor processor = new FileProcessor(file, latch, wordCount); processors.add(processor); processor.start(); } // Start result aggregator ResultAggregator aggregator = new ResultAggregator(latch, wordCount); aggregator.start(); // Monitor progress monitorProgress(processors, latch); // Wait for all threads to complete for (FileProcessor processor : processors) { processor.join(); } aggregator.join(); System.out.println("File processing completed."); // Cleanup sample files cleanupSampleFiles(); } private static void createSampleFiles() { File directory = new File("sample_files"); if (!directory.exists()) { directory.mkdir(); } String[] sampleTexts = { "Java is a programming language and computing platform", "Multithreading allows concurrent execution of two or more threads", "Threads can be created by extending Thread class or implementing Runnable", "Synchronization is important for thread safety in Java applications", "File processing with multiple threads can improve performance significantly" }; for (int i = 0; i < sampleTexts.length; i++) { try (PrintWriter writer = new PrintWriter(new File(directory, "file" + (i + 1) + ".txt"))) { // Write multiple lines to make files more substantial for (int j = 0; j < 10; j++) { writer.println(sampleTexts[i] + " - Line " + (j + 1)); } } catch (FileNotFoundException e) { e.printStackTrace(); } } System.out.println("Created " + sampleTexts.length + " sample files"); } private static void cleanupSampleFiles() { File directory = new File("sample_files"); if (directory.exists()) { File[] files = directory.listFiles(); if (files != null) { for (File file : files) { file.delete(); } } directory.delete(); System.out.println("Cleaned up sample files"); } } private static void monitorProgress(List<FileProcessor> processors, CountDownLatch latch) { Thread monitorThread = new Thread(() -> { while (latch.getCount() > 0) { System.out.printf("Progress: %d/%d files completed%n", processors.size() - latch.getCount(), processors.size()); try { Thread.sleep(500); } catch (InterruptedException e) { break; } } }, "Progress-Monitor"); monitorThread.setDaemon(true); monitorThread.start(); } }

Web Page Downloader with Threads

import java.io.*; import java.net.*; import java.util.*; import java.util.concurrent.*; public class WebPageDownloader { static class PageDownloader extends Thread { private String url; private String savePath; private CountDownLatch latch; public PageDownloader(String url, String savePath, CountDownLatch latch) { super("Downloader-" + new File(url).getName()); this.url = url; this.savePath = savePath; this.latch = latch; } @Override public void run() { System.out.println(getName() + " - Starting download: " + url); try { URL website = new URL(url); try (InputStream in = website.openStream(); FileOutputStream out = new FileOutputStream(savePath)) { byte[] buffer = new byte[1024]; int bytesRead; long totalBytes = 0; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); totalBytes += bytesRead; // Check for interruption if (Thread.currentThread().isInterrupted()) { System.out.println(getName() + " - Download interrupted"); return; } } System.out.println(getName() + " - Download completed: " + totalBytes + " bytes saved to " + savePath); } catch (IOException e) { System.err.println(getName() + " - Error downloading: " + e.getMessage()); } } catch (MalformedURLException e) { System.err.println(getName() + " - Invalid URL: " + url); } finally { latch.countDown(); } } } static class DownloadManager { private List<PageDownloader> downloaders = new ArrayList<>(); private CountDownLatch latch; public void addDownload(String url, String savePath) { if (latch != null) { throw new IllegalStateException("Downloads already started"); } downloaders.add(new PageDownloader(url, savePath, latch)); } public void startDownloads() throws InterruptedException { if (downloaders.isEmpty()) { System.out.println("No downloads added"); return; } latch = new CountDownLatch(downloaders.size()); // Update all downloaders with the latch for (PageDownloader downloader : downloaders) { // We need to recreate downloaders with the latch // This is a limitation of our current design } System.out.println("Starting " + downloaders.size() + " downloads..."); // Start all downloaders for (PageDownloader downloader : downloaders) { downloader.start(); } // Monitor progress monitorProgress(); // Wait for all downloads to complete latch.await(); System.out.println("All downloads completed!"); } public void stopAllDownloads() { System.out.println("Stopping all downloads..."); for (PageDownloader downloader : downloaders) { if (downloader.isAlive()) { downloader.interrupt(); } } } private void monitorProgress() { Thread monitor = new Thread(() -> { while (latch.getCount() > 0) { long completed = downloaders.size() - latch.getCount(); System.out.printf("Download Progress: %d/%d (%.1f%%)%n", completed, downloaders.size(), (completed * 100.0 / downloaders.size())); try { Thread.sleep(1000); } catch (InterruptedException e) { break; } } }, "Download-Monitor"); monitor.setDaemon(true); monitor.start(); } } public static void main(String[] args) throws InterruptedException { System.out.println("=== Web Page Downloader with Threads ==="); DownloadManager manager = new DownloadManager(); // Add some sample URLs (using small files for demonstration) manager.addDownload("https://www.example.com", "downloads/example.html"); manager.addDownload("https://httpbin.org/json", "downloads/json.json"); manager.addDownload("https://httpbin.org/xml", "downloads/xml.xml"); // Create downloads directory new File("downloads").mkdir(); // Start downloads try { manager.startDownloads(); } catch (InterruptedException e) { System.err.println("Download process interrupted"); manager.stopAllDownloads(); } // Demonstrate timeout mechanism demonstrateDownloadWithTimeout(); } public static void demonstrateDownloadWithTimeout() throws InterruptedException { System.out.println("\n=== Download with Timeout ==="); CountDownLatch latch = new CountDownLatch(1); PageDownloader slowDownloader = new PageDownloader( "https://httpbin.org/delay/5", // This URL delays response by 5 seconds "downloads/slow.html", latch ); slowDownloader.start(); // Wait for download with timeout boolean completed = latch.await(3, TimeUnit.SECONDS); // Wait max 3 seconds if (!completed) { System.out.println("Download timed out - interrupting..."); slowDownloader.interrupt(); slowDownloader.join(1000); // Wait for thread to finish } else { System.out.println("Download completed within timeout"); } if (slowDownloader.isAlive()) { System.out.println("Thread is still alive after interrupt, using stop (not recommended)"); // Note: Thread.stop() is deprecated and should be avoided } } }

Summary

Key Thread Class Methods:

  1. Lifecycle Methods:
  • start() - Begins thread execution
  • run() - Contains thread's code (override this)
  • join() - Waits for thread to die
  • interrupt() - Interrupts the thread
  1. State Methods:
  • getState() - Returns thread state
  • isAlive() - Tests if thread is alive
  • isInterrupted() - Tests if thread is interrupted
  1. Control Methods:
  • sleep() - Causes thread to sleep
  • yield() - Hint to scheduler to yield execution
  • setPriority() - Changes thread priority
  • setDaemon() - Marks as daemon thread

Thread States:

  • NEW - Created but not started
  • RUNNABLE - Executing in JVM
  • BLOCKED - Waiting for monitor lock
  • WAITING - Waiting indefinitely
  • TIMED_WAITING - Waiting with timeout
  • TERMINATED - Completed execution

Best Practices:

  1. Always check interruption status in long-running tasks
  2. Use synchronization for shared resources
  3. Prefer implementing Runnable over extending Thread for flexibility
  4. Use thread pools for managing multiple threads
  5. Handle InterruptedException properly
  6. Avoid Thread.stop() - use interruption instead
  7. Use daemon threads for background tasks that shouldn't prevent JVM exit

The Thread class provides the foundation for multithreading in Java, but for most applications, using the Executor framework (thread pools) is recommended for better resource management and control.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper