Поток демона с бесконечным циклом не завершается

У меня есть простая тестовая программа (симуляция гаража) с несколькими потоками (объекты Vehicle, MysteryVehicle, Observer), созданными и запущенными. Только объект Observer представляет собой поток демона, работающий в бесконечном цикле.

После завершения всех потоков, не являющихся демонами, поток Observer никогда не завершается, и цикл выполняется бесконечно (так что это не какой-то буферизованный вывод после того, как поток демона на самом деле завершается — он продолжается вечно).

Все потоки, не являющиеся демонами, выводят что-то на консоль непосредственно перед выходом из своих run() методов, и это ясно показывает, что все они действительно завершены. Я также не вызывал join() в потоке демона. При распечатке всех запущенных в данный момент потоков также отображается observer, поэтому я предполагаю, что этот поток демона не завершается должным образом.

Полный код можно найти в этой фиксации.

Ниже вы можете увидеть все темы, созданные, запущенные и где именно вызывается join().


Main.java

package garage;

import java.util.Set;

import garage.model.*;
import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        Platform platform = new Platform();
        Vehicle.platform = platform;
        platform.print();

        Vehicle[] vehicles = new Vehicle[30];
        for (int i = 0; i < 30; i++) {
            vehicles[i] = new Vehicle();
        }

        for (int i = 0; i < 30; i++) {
            vehicles[i].start();
        }

        Observer observer = new Observer();
        observer.platform = platform;
        observer.start();

        MysteryVehicle mysteryVehicle = new MysteryVehicle();
        mysteryVehicle.start();

        try {
            mysteryVehicle.join();
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        try {
            for (int i = 0; i < 30; i++)
                vehicles[i].join();
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        System.out.println("before");
        platform.print();
        System.out.println("after");

        synchronized (Platform.lock) {
            System.out.println("END");
            System.out.println(platform.flag); // checks whether wait() was called anytime
        }

        Set<Thread> threads = Thread.getAllStackTraces().keySet();

        for (Thread t : threads) {
            System.out.println(t.getName());
        }

    }

    public static void main(String[] args) {
        launch(args);
    }

}


Observer.java

package garage.model;

public class Observer extends Thread {
    public Platform platform;
    static int count = 0;

    {
        setName("observer");
        setPriority(MIN_PRIORITY);
        setDaemon(true);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (Platform.lock) {
                try {
                    System.out.println(++count);
                    platform.print();
                    Platform.lock.wait(5000); // hack for when there is no meaningful loop condition
                } catch (InterruptedException exception) {
                    exception.printStackTrace();
                } finally {
                    Platform.lock.notifyAll();
                }
            }
        }

    }

}


Метод Vehicle run() – соответствующая часть

public void run() {
        ... 
    System.out.println("done");
}


Метод MysteryVehicle run() – соответствующая часть

public void run() {
        synchronized (Platform.lock) {
            System.out.println("And the vehicle disappears!");
            ...
        }

    }


Все соответствующие сообщения потока выводятся на консоль. сделано - 30 раз, И машина исчезает!, до, после, КОНЕЦ, правда

Это список всех запущенных потоков:

Attach Listener
main
Common-Cleaner
JavaFX Application Thread
Signal Dispatcher
Finalizer
InvokeLaterDispatcher
Reference Handler
QuantumRenderer-0
observer
Thread-2
JavaFX-Launcher

Поскольку программа не завершается, а функция print() вызывает run() метод observer, что мешает завершению потока демона?

Что мне здесь не хватает?


person 0lt    schedule 21.12.2018    source источник
comment
что препятствует завершению потока демона? Я думаю, что это код его метода запуска, который имеет бесконечный цикл и не имеет оператора возврата.   -  person Alexei Kaigorodov    schedule 21.12.2018
comment
Platform.exit() не вызывается, и нет никаких объектов пользовательского интерфейса, которые нужно закрыть, поэтому действительно ли возвращается main()? Попробуйте добавить println() после launch().   -  person Andrew S    schedule 21.12.2018
comment
Re, после завершения всех потоков, не являющихся демонами... Не забывайте, что main() вызывается потоком, не являющимся демоном.   -  person Solomon Slow    schedule 21.12.2018


Ответы (2)


Я подозреваю, что main() никогда не вернется, поэтому основной поток (и, возможно, некоторые из этих потоков FX) все еще работают.

Из Документация по заявке:

Метод запуска не возвращает значение до тех пор, пока приложение не завершит работу либо с помощью вызова Platform.exit, либо пока не будут закрыты все окна приложения.

Опубликованный код не имеет окна для закрытия и не вызывается Platform.exit().

person Andrew S    schedule 21.12.2018
comment
Да, это было. У меня никогда не было необходимости в бесконечном цикле внутри потока демона, поддерживающего его в рабочем состоянии, пока работает основной поток. Обычно они заканчивались после выполнения определенного условия, поэтому я понятия не имел. - person 0lt; 21.12.2018

Насколько я знаю, вызов соединения с потоком демона - плохая идея. Идея использования потока демона заключается в том, что он не остановит выход JVM. Что вы можете сделать, так это отправить прерывание этому потоку и после этого вызвать соединение.

person Mukesh Verma    schedule 21.12.2018
comment
Как я уже сказал, я не вызывал join() в потоке демона, и программа все еще останавливается. - person 0lt; 21.12.2018
comment
@0lt От 2-го до последнего абзаца в вашем исходном вопросе говорится: «Поскольку программа не завершается..., но в вашем комментарии выше говорится, что... и программа все еще останавливается. Что это? Процесс прекращается? или процесс не завершается? - person Solomon Slow; 21.12.2018
comment
@SolomonSlow, плохо, это не останавливается. Программа никогда не завершается. - person 0lt; 21.12.2018