Search code examples
javamultithreadingconcurrency

How to stop a Java thread without an exit flag


My M(Non)WE is as follows:

public class SOQuestion1 {

    public static void main(String[] args) {
        ProducerThread producerThread1 = new ProducerThread();
        ProducerThread producerThread2 = new ProducerThread();
        
        ControllerThread1 controllerThread1 = 
                new ControllerThread1(producerThread1);
        
        controllerThread1.start();
        
        ControllerThread2 controllerThread2 = 
                new ControllerThread2(producerThread2);
        
        controllerThread2.start();
    }
}

class ProducerThread extends Thread {
    
    @Override
    public void run() {
        while (true);
    }
}

class ControllerThread1 extends Thread {
    
    private final ProducerThread producerThread;
    
    ControllerThread1(ProducerThread producerThread) {
        this.producerThread = producerThread;
    }
    
    @Override
    public void run() {
        producerThread.start();
        System.out.println("Started ControllerThread1.");
        
        try {
            producerThread.join(2000);
            
            Thread.sleep(2000);
            producerThread.interrupt();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        
        System.out.println("Joined ControllerThread1.");
    }
}

class ControllerThread2 extends Thread {
    
    private final ProducerThread producerThread;
    
    ControllerThread2(ProducerThread producerThread) {
        this.producerThread = producerThread;
    }
    
    @Override
    public void run() {
        producerThread.start();
        System.out.println("Started ControllerThread2.");
        
        try {
            Thread.sleep(2000);
            producerThread.interrupt();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        
        System.out.println("Joined ControllerThread2.");
    }
}

It outputs:

Started ControllerThread1.
Started ControllerThread2.
Joined ControllerThread2.
Joined ControllerThread1.

... and the producer threads remain running.

Here is, however, a constraint: since my future producer thread will load data from internet, there is not telling how fast the server will respond, and so, I cannot rely on flags in the producer threads.

Is there a way to solve this issue without using the thread continuation flags.?


Solution

  • Very simple. Make the ProducerThreads daemon threads. By default, they are not. In the below code I simply added two lines that explicitly set the created ProducerThreads as daemon threads.

    public class SOQuestion1 {
    
        public static void main(String[] args) {
            ProducerThread producerThread1 = new ProducerThread();
            producerThread1.setDaemon(true); // ADDED
            ProducerThread producerThread2 = new ProducerThread();
            producerThread2.setDaemon(true); // ADDED
    
            ControllerThread1 controllerThread1 = new ControllerThread1(producerThread1);
            controllerThread1.start();
    
            ControllerThread2 controllerThread2 = new ControllerThread2(producerThread2);
            controllerThread2.start();
        }
    }
    
    class ProducerThread extends Thread {
    
        @Override
        public void run() {
            while (true)
                ;
        }
    }
    
    class ControllerThread1 extends Thread {
        private final ProducerThread producerThread;
    
        ControllerThread1(ProducerThread producerThread) {
            this.producerThread = producerThread;
        }
    
        @Override
        public void run() {
            producerThread.start();
            System.out.println("Started ControllerThread1.");
            try {
                producerThread.join(2000);
                Thread.sleep(2000);
                producerThread.interrupt();
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            System.out.println("Joined ControllerThread1.");
        }
    }
    
    class ControllerThread2 extends Thread {
        private final ProducerThread producerThread;
    
        ControllerThread2(ProducerThread producerThread) {
            this.producerThread = producerThread;
        }
    
        @Override
        public void run() {
            producerThread.start();
            System.out.println("Started ControllerThread2.");
            try {
                Thread.sleep(2000);
                producerThread.interrupt();
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            System.out.println("Joined ControllerThread2.");
        }
    }
    

    Here is the output when I run the above code:

    Started ControllerThread1.
    Started ControllerThread2.
    Joined ControllerThread2.
    Joined ControllerThread1.
    

    After the last line of output is displayed, the JVM terminates.