Не удается закрыть все потоки AWT при выходе

Я пытаюсь закрыть свое Java-приложение, но потоки остаются открытыми.

При нажатии кнопки закрытия с помощью кнопки x по умолчанию в Windows все закрывается нормально (вероятно, из-за EXIT_ON_CLOSE?), Но когда я использую программную кнопку, она зависает на thread.join ().

Хуже того, окно расположено нормально, поэтому пользователь может подумать, что оно закрыто, но есть несколько потоков AWT, которые остаются открытыми. Мой основной поток ожидает потока с идентификатором 20, но я понятия не имею, как получить идентификаторы потока.

У кого-нибудь есть предложения?

Вот мой код выхода:

public synchronized void stop() {
    running = false;
    frame.dispose();
    WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
    try {
        if (server != null) {
            server.exit();
        }
        client.exit();
        thread.join();
        new Thread(){
            public void run() {
                System.exit(0);
            }
        }.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        e.printStackTrace();
        System.exit(1);
    }
}

и вот потоки, открытые после выхода:

thread-eclipse

а вот содержимое моего run() метода:

public void run() {
    requestFocus();
    while (running) {
        getTimer().tick();
        if (System.currentTimeMillis() - getTimer().getSecond() > 1000) {
            // every second, add a second, print fps and mod title with fps
            getTimer().accumulateSecond();
            //System.out.println(getTimer().returnFPS());
            frame.setTitle(title + "  |  " + getTimer().returnFPS());
            getTimer().resetTick();
            ticker++;
        }
        while (getTimer().getDelta() >= 1) {
            // every time delta goes greater than one, update and supertick
            update();
            getTimer().superTick();
        }
        if (getTimer().getFPS() > 100) {
            try {
                Thread.sleep(5);
            } catch (Exception e) {
                System.err.println("Sleeping failed: " + e);
            }
        } 
        render();
        if (ticker > 30) {
            ticker = 0;
            getTimer().hourTick();
        }

    }
    stop();
}

person gossfunkel    schedule 30.05.2013    source источник
comment
перемещение System.exit(0) временного потока выше join() позволяет полностью закрыть его, но я сомневаюсь, что это потокобезопасно?   -  person gossfunkel    schedule 31.05.2013
comment
пожалуйста, по какой причине не хватает этого здесь, может ли это быть неправильно,   -  person mKorbel    schedule 31.05.2013
comment
Является ли метод run(), который вы показываете во внутреннем Thread классе, в том же классе, что и метод stop() выше? Существуют ли какие-либо другие вызовы в run(), которые вызывают synchronized методы?   -  person Nate    schedule 02.06.2013


Ответы (1)


Обновление:

Увидев больше вашего кода, я почти уверен, что ваша проблема в том, что вы вызываете stop() (то есть synchronized) из одного потока. Внутри stop() вы вызываете thread.join(), который пытается дождаться, пока экземпляр thread завершит свой run() метод. Установка флага running заставляет run() выйти из цикла while, но последняя строка кода в методе - это еще один вызов stop(). Если это тот же stop() метод, который вы нам показали, то у вас тупик.

Вызов stop() внутри вашего run() метода никогда не сможет войти в метод, потому что первый поток все еще находится внутри stop() и ожидает завершения run() (чего никогда не будет, потому что он ожидает возможности вызвать и ввести stop()). Тупик.

Вам нужно будет удалить вызов stop() изнутри run() или найти другой способ переделать свой код.


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

Прежде всего, Thread#join() не останавливает поток. Он ждет его завершения. Что-то еще, что вы делаете, должно вызвать / позволить экземпляру thread завершить свой run() метод.

Единственное, что я могу сделать, это установить

    running = false;

Проверяет ли ваш thread объект этот флаг внутри своего run() метода? Например:

public void run() {
    while (isRunning()) {

        // do some work
        Thread.sleep(delay);
    }
}

где isRunning() вернет вам значение переменной running?

Я не могу сказать, не увидев больше вашего кода. Однако вы могли выбрать реализацию isRunning() следующим образом:

public synchronized boolean isRunning() {
    return running;
}

Если вы это сделали, то возникла проблема. Основной поток получит блокировку в stop() методе, который вы нам показали. Затем он переходит к вызову thread.join(), после чего начинает ждать рабочий поток. Если рабочий поток затем вызывает isRunning(), который синхронизируется с той же блокировкой, тогда isRunning() будет заблокирован, потому что блокировка уже удерживается в силу того, что основной поток находится внутри stop().

Та же самая основная проблема может возникнуть, если объект thread пытается вызвать любой другой synchronized метод из класса, код которого вы нам показали.

Короче говоря, нам нужно увидеть еще код (то, что выполняется в потоке, представленном переменной thread). Но, возможно, вы зашли в тупик.

Подробнее об изящной остановке потока здесь

person Nate    schedule 31.05.2013
comment
Метод run() проверяет running напрямую, и да, все это находится прямо внутри него. Я считаю, что он ожидает закрытия какой-то подпотки, но я не могу ее идентифицировать. Не так много синхронизированных методов, не так много ресурсов, которые могут стать несинхронизированными. - person gossfunkel; 31.05.2013
comment
Мы не сможем вам помочь, если вы не покажете нам этот код (код, который выполняется внутри метода run(), переданного объекту thread). То, что вы показали, недостаточно для устранения проблемы, за исключением предположения, которое я уже сделал. - person Nate; 31.05.2013
comment
@gossfunkel, если из run() вызывается тот же метод stop(), то это ваша проблема. stop() равно synchronized, поэтому thread не сможет войти в stop(), поскольку другой поток уже внутри stop(), ожидая в thread.join(). - person Nate; 02.06.2013
comment
милый Иисус, ты прав. Это было поразительно глупо, ужасно жаль! к сожалению, это не решило проблему. - person gossfunkel; 02.06.2013
comment
Подожди, я не понимаю. Это был тот же вызов stop()? Если так, то это проблема. Если вы по-прежнему не видите, что нить умирает, значит, у вас также другая проблема. Но поскольку мы не видим определения других ваших методов, трудно сказать, что еще может быть неправильным. - person Nate; 02.06.2013
comment
Похоже, у меня другая проблема! Осмелюсь сказать, что мне просто нужно использовать исправление, которое у меня есть прямо сейчас, и решить его должным образом, когда я смогу определить проблему. - person gossfunkel; 02.06.2013
comment
@gossfunkel, пожалуйста, не задавайте вопросов, а затем решайте, что решение вам действительно не нужно. Это напрасная трата времени людей, которые находят время, чтобы помочь вам (бесплатно). - person Nate; 02.06.2013
comment
Необходимость все еще существует, но спешить с поиском решения не приходится. Большое спасибо за помощь, я просто сказал, что это не помогло, и что я мог бы подождать, изучая исправление в долгосрочной перспективе, если ответ сейчас недоступен. - person gossfunkel; 02.06.2013