Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Java Multithreading Implementation and Thread Synchronization

Tech 1

Process and Thread Fundamentals

Processes maintain independent memory spaces and code segments, requiring significant overhead for context switching. Each process can contain multiple threads. Threads within the same process share memory and code space but maintain separate execution stacks and program counters, enabling lightweight context switching.

Both processes and threads follow five lifecycle stages: creation, ready, running, blocked, and termination. Multiprocessing enables concurrent execution of multiple applications, while multithreading allows multiple sequential flows within a single program.

Creating Threads in Java

Java provides two primary approaches for thread creation: extending the Thread class or implementing the Runnable interface.

Extending Thread Class

class WorkerThread extends Thread {
    private String identifier;
    
    public WorkerThread(String id) {
        this.identifier = id;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(identifier + " executing : " + i);
            try {
                Thread.sleep((int) (Math.random() * 10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Application {
    public static void main(String[] args) {
        WorkerThread threadA = new WorkerThread("X");
        WorkerThread threadB = new WorkerThread("Y");
        threadA.start();
        threadB.start();
    }
}

The start() method transitions threads to runnable state, with actual execution timing determined by the operating system scheduler. Thread.sleep() yields CPU resources to other threads during execusion.

Implementing Runnable Interface

class TaskRunner implements Runnable {
    private String label;
    
    public TaskRunner(String label) {
        this.label = label;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(label + " executing : " + i);
            try {
                Thread.sleep((int) (Math.random() * 10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Executor {
    public static void main(String[] args) {
        new Thread(new TaskRunner("M")).start();
        new Thread(new TaskRunner("N")).start();
    }
}

Thread vs Runnable Comparison

Inheritance-based threading creates isolated resource instances, while Runnable implementation anables resource sharing across threads.

class SharedCounter implements Runnable {
    private int sharedValue = 15;
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + 
                             " processing value= " + sharedValue--);
            try {
                Thread.sleep((int) (Math.random() * 10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class ResourceCoordinator {
    public static void main(String[] args) {
        SharedCounter counter = new SharedCounter();
        new Thread(counter, "Alpha").start();
        new Thread(counter, "Beta").start();
        new Thread(counter, "Gamma").start();
    }
}

Runnable implementation offers advantages including resource sharing capabilities, avoidance of Java's single inheritance limitation, and enhanced code modularity.

Thread Lifecycle States

  1. New: Thread instance created
  2. Runnable: Thread eligible for CPU execution after start() invocation
  3. Running: Thread actively executing code
  4. Blocked: Thread suspended due to various conditions:
    • Wait blocking: Thread in waiting pool after wait() call
    • Synchronization blocking: Thread in lock pool awaiting monitor acquisition
    • General blocking: Thread suspended during sleep(), join(), or I/O operations
  5. Terminated: Thread completed execution or exited via exception

Thread Scheduling Mechanisms

Priority Management

Thread priorities range from 1 (MIN_PRIORITY) to 10 (MAX_PRIORITY), with default priority set to 5 (NORM_PRIORITY). Priority inheritance occurs when threads spawn child threads.

Thread Control Methods

  • sleep(long millis): Temporarily suspends thread execution
  • wait(): Places thread in waiting state until notified
  • yield(): Voluntarily yields CPU to threads of equal or higher priority
  • join(): Suspends calling thread until target thread completes
  • notify()/notifyAll(): Wakes waiting threads on object monitor

Join Method Implementation

class ComputationThread extends Thread {
    private String name;
    
    public ComputationThread(String name) {
        super(name);
        this.name = name;
    }
    
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " started computation");
        for (int i = 0; i < 5; i++) {
            System.out.println("Processing " + name + " : " + i);
            try {
                sleep((int) (Math.random() * 10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " completed");
    }
}

class Coordinator {
    public static void main(String[] args) {
        System.out.println("Main thread initiating");
        ComputationThread worker1 = new ComputationThread("A");
        ComputationThread worker2 = new ComputationThread("B");
        
        worker1.start();
        worker2.start();
        
        try {
            worker1.join();
            worker2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Main thread terminating");
    }
}

Synchronization Primitives

Wait/Notify Coordination

class SequentialPrinter implements Runnable {
    private String identifier;
    private Object previous;
    private Object current;
    
    public SequentialPrinter(String id, Object prev, Object curr) {
        this.identifier = id;
        this.previous = prev;
        this.current = curr;
    }
    
    @Override
    public void run() {
        int iterations = 10;
        while (iterations > 0) {
            synchronized (previous) {
                synchronized (current) {
                    System.out.print(identifier);
                    iterations--;
                    current.notify();
                }
                try {
                    previous.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class SynchronizationDemo {
    public static void main(String[] args) throws Exception {
        Object lockA = new Object();
        Object lockB = new Object();
        Object lockC = new Object();
        
        SequentialPrinter printerA = new SequentialPrinter("A", lockC, lockA);
        SequentialPrinter printerB = new SequentialPrinter("B", lockA, lockB);
        SequentialPrinter printerC = new SequentialPrinter("C", lockB, lockC);
        
        new Thread(printerA).start();
        Thread.sleep(100);
        new Thread(printerB).start();
        Thread.sleep(100);
        new Thread(printerC).start();
        Thread.sleep(100);
    }
}

Data Exchange Between Threads

Constructor-based Data Transfer

class ParameterizedThread extends Thread {
    private String message;
    
    public ParameterizedThread(String msg) {
        this.message = msg;
    }
    
    @Override
    public void run() {
        System.out.println("Greetings " + message);
    }
}

class ThreadLauncher {
    public static void main(String[] args) {
        Thread worker = new ParameterizedThread("universe");
        worker.start();
    }
}

Method-based Data Assignment

class ConfigurableTask implements Runnable {
    private String message;
    
    public void setMessage(String msg) {
        this.message = msg;
    }
    
    @Override
    public void run() {
        System.out.println("Greetings " + message);
    }
}

class TaskExecutor {
    public static void main(String[] args) {
        ConfigurableTask task = new ConfigurableTask();
        task.setMessage("universe");
        Thread worker = new Thread(task);
        worker.start();
    }
}

Callback Pattern for Dynamic Data

class ResultContainer {
    public int sum = 0;
}

class Calculator {
    public void computeSum(ResultContainer result, int... numbers) {
        for (int num : numbers) {
            result.sum += num;
        }
    }
}

class ComputationalThread extends Thread {
    private Calculator processor;
    
    public ComputationalThread(Calculator calc) {
        this.processor = calc;
    }
    
    @Override
    public void run() {
        java.util.Random generator = new java.util.Random();
        ResultContainer outcome = new ResultContainer();
        int val1 = generator.nextInt(1000);
        int val2 = generator.nextInt(2000);
        int val3 = generator.nextInt(3000);
        
        processor.computeSum(outcome, val1, val2, val3);
        System.out.println(val1 + "+" + val2 + "+" + val3 + "=" + outcome.sum);
    }
}

class CallbackDemo {
    public static void main(String[] args) {
        Thread computation = new ComputationalThread(new Calculator());
        computation.start();
    }
}
Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.