Chapter 13: Multithreading

Introduction to Multithreading

Multiprocessing and multithreading both are used to achieve multitasking.

Multithreading allows concurrent execution of multiple parts of a program for maximum utilization of CPU.

Process vs Thread

Multiprocessing

Process 1
Separate Memory
Process 2
Separate Memory
Process 3
Separate Memory
Operating System

Multithreading

Process
Thread 1
Thread 2
Thread 3
Shared Memory Area

Thread Advantages

  • Shared Memory: Threads use shared memory area
  • Faster Context Switching: Less overhead than processes
  • Lightweight: Thread is lighter than process
  • Resource Sharing: Efficient resource utilization
  • Real-world Example

    Word Processor:

  • One thread running in foreground as an editor
  • Another thread in background auto-saving the document
  • Third thread checking spelling and grammar
  • Creating a Thread

    There are two ways to create a thread in Java:

  • By extending Thread Class
  • By implementing Runnable interface
  • Method 1: Extending Thread Class

    ThreadByExtending.java
    class MyThread extends Thread {
        @Override
        public void run() {
            // Code that will run in separate thread
            for (int i = 1; i <= 5; i++) {
                System.out.println("Thread: " + Thread.currentThread().getName() + 
                                 ", Count: " + i);
                try {
                    Thread.sleep(1000); // Sleep for 1 second
                } catch (InterruptedException e) {
                    System.out.println("Thread interrupted");
                }
            }
        }
    }
    
    public class ThreadByExtending {
        public static void main(String[] args) {
            MyThread thread1 = new MyThread();
            MyThread thread2 = new MyThread();
            
            thread1.setName("Worker-1");
            thread2.setName("Worker-2");
            
            thread1.start(); // Start first thread
            thread2.start(); // Start second thread
            
            System.out.println("Main thread continues...");
        }
    }

    Method 2: Implementing Runnable Interface

    ThreadByRunnable.java
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 1; i <= 5; i++) {
                System.out.println("Runnable: " + Thread.currentThread().getName() + 
                                 ", Count: " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("Thread interrupted");
                }
            }
        }
    }
    
    public class ThreadByRunnable {
        public static void main(String[] args) {
            MyRunnable runnable1 = new MyRunnable();
            MyRunnable runnable2 = new MyRunnable();
            
            Thread thread1 = new Thread(runnable1, "Worker-1");
            Thread thread2 = new Thread(runnable2, "Worker-2");
            
            thread1.start();
            thread2.start();
            
            System.out.println("Main thread continues...");
        }
    }

    Extending Thread Class

    Pros:

  • Simple to implement
  • Direct access to Thread methods
  • Cons:

  • Cannot extend other classes
  • Tight coupling with Thread class
  • Implementing Runnable

    Pros:

  • Can extend other classes
  • Better object-oriented design
  • Separation of concerns
  • Cons:

  • Slightly more code
  • Need Thread object to start
  • Life Cycle of a Thread

    A thread goes through various states during its lifetime.

    State Descriptions

    1. New

    Instance of thread created which is not yet started by invoking start().

    Thread t = new Thread();

    2. Runnable

    After invocation of start() & before it is selected to be run by the scheduler.

    t.start();

    3. Running

    After thread scheduler has selected it for execution.

    // Thread is executing run() method

    4. Non-Runnable (Blocked)

    Thread alive, but not eligible to run due to waiting, sleeping, or blocking.

    Thread.sleep(1000); // or wait(), join()

    5. Terminated

    run() method has exited - thread execution completed.

    // Thread finished execution

    The Thread Class

    Below are the commonly used Constructors of Thread class:

    Thread Constructors

    Constructor Description Example
    Thread() Creates a new thread with default name Thread t = new Thread();
    Thread(String name) Creates a new thread with specified name Thread t = new Thread("MyThread");
    Thread(Runnable r) Creates a new thread with Runnable target Thread t = new Thread(runnable);
    Thread(Runnable r, String name) Creates a new thread with Runnable and name Thread t = new Thread(runnable, "MyThread");
    ThreadConstructorExample.java
    class TaskRunnable implements Runnable {
        private String taskName;
        
        public TaskRunnable(String taskName) {
            this.taskName = taskName;
        }
        
        @Override
        public void run() {
            for (int i = 1; i <= 3; i++) {
                System.out.println(taskName + " - Step " + i + 
                                 " [Thread: " + Thread.currentThread().getName() + "]");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("Thread interrupted");
                }
            }
        }
    }
    
    public class ThreadConstructorExample {
        public static void main(String[] args) {
            // Constructor 1: Thread()
            Thread thread1 = new Thread() {
                @Override
                public void run() {
                    System.out.println("Anonymous thread running: " + getName());
                }
            };
            
            // Constructor 2: Thread(String name)
            Thread thread2 = new Thread("NamedThread") {
                @Override
                public void run() {
                    System.out.println("Named thread running: " + getName());
                }
            };
            
            // Constructor 3: Thread(Runnable r)
            TaskRunnable task1 = new TaskRunnable("Task1");
            Thread thread3 = new Thread(task1);
            
            // Constructor 4: Thread(Runnable r, String name)
            TaskRunnable task2 = new TaskRunnable("Task2");
            Thread thread4 = new Thread(task2, "CustomWorker");
            
            // Start all threads
            thread1.start();
            thread2.start();
            thread3.start();
            thread4.start();
            
            System.out.println("All threads started from main thread: " + 
                             Thread.currentThread().getName());
        }
    }

    Methods of Thread Class

    Thread class offers a lot of methods such as run(), start(), join(), getPriority(), setPriority() etc.

    More can be found by visiting Java docs.

    Important Thread Methods

    Method Description Example
    start() Starts the thread execution thread.start();
    run() Contains the code to be executed public void run() { ... }
    sleep(long ms) Pauses thread for specified milliseconds Thread.sleep(1000);
    join() Waits for thread to complete thread.join();
    getName() Returns thread name String name = thread.getName();
    setName(String) Sets thread name thread.setName("Worker");
    getPriority() Returns thread priority (1-10) int priority = thread.getPriority();
    setPriority(int) Sets thread priority (1-10) thread.setPriority(Thread.MAX_PRIORITY);
    isAlive() Checks if thread is alive boolean alive = thread.isAlive();
    currentThread() Returns reference to current thread Thread current = Thread.currentThread();
    ThreadMethodsExample.java
    class WorkerThread extends Thread {
        public WorkerThread(String name) {
            super(name);
        }
        
        @Override
        public void run() {
            System.out.println(getName() + " started with priority: " + getPriority());
            
            for (int i = 1; i <= 5; i++) {
                System.out.println(getName() + " - Task " + i);
                try {
                    Thread.sleep(500); // Sleep for 500ms
                } catch (InterruptedException e) {
                    System.out.println(getName() + " was interrupted");
                    return;
                }
            }
            
            System.out.println(getName() + " completed");
        }
    }
    
    public class ThreadMethodsExample {
        public static void main(String[] args) {
            System.out.println("Main thread: " + Thread.currentThread().getName());
            
            // Create threads
            WorkerThread worker1 = new WorkerThread("Worker-1");
            WorkerThread worker2 = new WorkerThread("Worker-2");
            WorkerThread worker3 = new WorkerThread("Worker-3");
            
            // Set priorities
            worker1.setPriority(Thread.MIN_PRIORITY);  // 1
            worker2.setPriority(Thread.NORM_PRIORITY); // 5
            worker3.setPriority(Thread.MAX_PRIORITY);  // 10
            
            // Start threads
            worker1.start();
            worker2.start();
            worker3.start();
            
            // Check if threads are alive
            System.out.println("Worker1 alive: " + worker1.isAlive());
            System.out.println("Worker2 alive: " + worker2.isAlive());
            System.out.println("Worker3 alive: " + worker3.isAlive());
            
            try {
                // Wait for all threads to complete
                worker1.join();
                worker2.join();
                worker3.join();
            } catch (InterruptedException e) {
                System.out.println("Main thread interrupted");
            }
            
            System.out.println("All workers completed. Main thread ending.");
        }
    }

    Thread Priorities

    Java threads have priorities ranging from 1 to 10:

  • Thread.MIN_PRIORITY = 1
  • Thread.NORM_PRIORITY = 5 (default)
  • Thread.MAX_PRIORITY = 10
  • Note: Thread priority is a hint to the thread scheduler. The actual behavior depends on the underlying operating system.

    Practice Set

    Chapter 13 - Practice Set

    1. Continuous Messages

    Write a program to print "Good morning" and "Welcome" continuously on the screen in Java using Threads.

    2. Thread Sleep

    Add a sleep method in welcome thread of question 1 to delay its execution for 200 ms.

    3. Priority Methods

    Demonstrate getPriority() and setPriority() methods in Java Threads.

    4. Thread State

    How do you get state of a given thread in Java?

    5. Current Thread Reference

    How do you get reference to the current thread in Java?

    Solution Example: Continuous Messages with Sleep

    Solution Example: Thread State and Current Thread

    ← Previous: Packages Next: Exceptions →