Как остановить поток Java без флага выхода

Мой M(Non)WE выглядит следующим образом:

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.");
    }
}

Он выводит:

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

... и потоки-производители продолжают работать.

Однако здесь есть ограничение: поскольку мой будущий поток-производитель будет загружать данные из Интернета, неизвестно, как быстро ответит сервер, и поэтому я не могу полагаться на флаги в потоках-производителях.

Есть ли способ решить эту проблему без использования флагов продолжения потока?

Что именно вы подразумеваете под «флагами продолжения потока»? Это встроенный механизм Java или что-то, что вы создаете в своем коде?

cyberbrain 18.03.2024 08:42

По сути, я хотел сказать, что логический флаг в бесконечном цикле потока невозможен. Мой поток-производитель вызовет метод, который в худшем случае блокируется на неопределенный срок.

coderodde 18.03.2024 08:45

Я бы использовал неблокирующий ввод-вывод для потока-производителя, таким образом вы можете использовать любую синхронизацию потоков, которую вы предпочитаете.

cyberbrain 18.03.2024 09:02

На самом деле это может не быть решением вашего требования «Я не могу полагаться на флаги в потоках производителя», но для проблемы в вашем примере, когда ваш поток производителя продолжает работать, если вы хотите прервать поток, вам нужно разрешить поток быть прерванным. вместо while(true) должно быть while(!Thread.isInterrupted())

BIBOO unit 18.03.2024 09:10

@BIBOOnation Хороший вариант, но он не соответствует моим требованиям.

coderodde 18.03.2024 09:25

@cyberbrain Не могли бы вы уточнить, что вы имеете в виду под неблокирующим вводом-выводом? Как насчет ответа?

coderodde 18.03.2024 09:46

К сожалению, сейчас я не могу дать вам готовый ответ, так как сам не часто им пользуюсь. Но я имел в виду использование вызовов в пакете java.nio вместо java.io (если вы используете стандартную Java) или использование таких фреймворков, как Spring WebFlux.

cyberbrain 18.03.2024 09:58

Простите за мое плохое понимание, но вы спрашиваете, как прекратить действие ProducerThread после того, как ControllerThread1 и ControllerThread2 завершились?

Abra 18.03.2024 11:06

@Абра, нет плохого понимания. Вы поняли это совершенно правильно.

coderodde 18.03.2024 11:21

Если вы загружаете через HTTP(S), вы можете рассмотреть возможность использования java.net.http.HttpClient, метод send которого можно прервать.

VGR 18.03.2024 13:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
10
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Очень просто. Создайте поток демона ProducerThreads s. По умолчанию это не так. В приведенном ниже коде я просто добавил две строки, которые явно устанавливают созданные ProducerThread как потоки демона.

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.");
    }
}

Вот результат, когда я запускаю приведенный выше код:

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

После отображения последней строки вывода JVM завершает работу.

Именно то, что я искал, спасибо!

coderodde 19.03.2024 07:17

Другие вопросы по теме