Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2      [все]
 Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
Всем привет!
Задача такая: веб-приложение при старте должно запускать несколько процессов (заранее неизвестно сколько), которые должны шуршать в фоне.
Делаю на грубом примере так:
+
package com.mycompany.testweb;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DaemonClass implements Runnable{

    @Override
    public void run() {
        String filePath = "D:\\myfile.txt";
        String text = "Ку!\n";

        while (true) {
            try {
                Files.write(Paths.get(filePath), text.getBytes(), StandardOpenOption.APPEND);
            } catch (IOException e) {
                System.out.println(e);
            }

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(DaemonClass.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }    
}

package com.mycompany.testweb;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class IniClass implements ServletContextListener {
    private Thread thread;
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        DaemonClass daemonClass = new DaemonClass();
         thread = new Thread(daemonClass);
         thread.start();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        thread.interrupt();
    }
    
}

Все работает.
Но потом делаем undeploy приложения, а файл все равно пишется.
Похоже, что при андеплое приложения не приходим в contextDestroyed.
Остановить можно только андеплой плюс рестарт веб-сервера.
Возникает вопрос как сделать, чтобы "дочерний" поток прерывался при дисейбле/андеплое приложения на сервере.
Переписываем в зародыш маленького ада:
+
package com.mycompany.testweb;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class IniClass implements ServletContextListener, Runnable {
    private Thread mainThread;
    private Thread thread;
    private DaemonClass daemonClass = null;
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        mainThread = new Thread(this);
        mainThread.start();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        daemonClass.setIsInterrupted(true);
        thread.interrupt();
    }

    @Override
    public void run() {
        daemonClass = new DaemonClass();
        thread = new Thread(daemonClass);
        thread.start();
    }
}

И каким-то чудом теперь все работает как требуется.
Но хотелось бы понять, в чем фишка?
Почему работает в данном случае как надо, только если лисенер сам себя засовывает в поток?
(как понял, только в этом случае приходим в contextDestroyed).
И возможно, как реализовать правильнее?
24 июл 19, 19:27    [21933842]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 9430
"Веб-приложение" работает в сервлет-контейнер.
Жизненный цикл сервлета предусматривает методы init() и destroy().
Метод destroy() должен выставить флаг "кончай работу" и любым способом контролировать число оставшихся в работе потоков
Ваш(и) метод(ы) обязан(ы) регулярно проверять этот флаг, чтобы иметь возможность корректно завершаться без ударов киянкой по голове.
24 июл 19, 19:50    [21933849]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
Basil A. Sidorov, это понятно. Но даже если вместо interrupt использовать флаг, который при выставлении в contextDestroyed выходит из цикла в методе run, поведение получается точно такое же (поток не останавливается при undeploy/disable).
Понятно, что по флагу правильнее "мягче", но вопрос в том почему второй вариант работает и мы приходим в contextDestroyed, а первый нет.
24 июл 19, 21:11    [21933882]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
каким-то чудом теперь все работает как требуется.
про чудо потом. Ты скажи что он пишет в файл, если старший ушел с сервера? Может это и правильно, не вырубать его? Посреди работы?
24 июл 19, 21:21    [21933889]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp, пишет ровно то, что в коде "Ку!".
Вырубать его однозначно надо. По флагу или нет, вопрос не в этом.
24 июл 19, 22:00    [21933903]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2561
JDS
И каким-то чудом теперь все работает как требуется.
Но хотелось бы понять, в чем фишка?
Почему работает в данном случае как надо, только если лисенер сам себя засовывает в поток?
(как понял, только в этом случае приходим в contextDestroyed).
И возможно, как реализовать правильнее?


дружище ты никогда не станешь программистом нормальным если будешь задавать такие вопросы
другими словами ты забиваешь свою голову тем,что тебе не нужно )
сделал - работает - расслабь булки и получай удовольствие
24 июл 19, 22:32    [21933918]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
Вырубать его однозначно надо
в оракле вырубается набором kill.
Поэтому хороший поток кончить должен" (с)
24 июл 19, 23:01    [21933940]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
asv79, главное не купить билет на самолет, автопилот к которому сам же написал по такому принципу
PetroNotC Sharp, про оракле не понял)
25 июл 19, 07:57    [21934006]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS,
В оракле и линуксе я кончаю поток набором kill в командной строке.
Почему у тебя поток работает без бензина ты не рассказал.
Может его изменить так чтобы он работал только под конкретную задачу, 1-10 сек.
Приложение выгрузил (а не выдернул из розетки) и поток доделал свою задачу.
Это вопрос чисто по постановке.
25 июл 19, 08:12    [21934012]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp, в том и дело, что без бензина не надо работать (если это про ведущий поток). Да, можно завершить нормально без прерывания, но вопрос другой. Насчет кил операционкой "это же не наш метод" (с) )
25 июл 19, 08:57    [21934025]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
что без бензина не надо работать (если это про ведущий поток).
у тебя не ведущий и не основной. На основном томкат сидит.
Доп.поток создал ты сам. Почему он не заканчивает а крутится на бесконечном цикле?
25 июл 19, 09:42    [21934045]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS,
Пример.
Сброс кэша в лог файл.
Приложение закрыл, а в файл записывается и дескриптор закрывается.
Почему у тебя не так?
25 июл 19, 09:45    [21934050]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp, это понятно что сам.
Например, он должен периодически проверять директорию на предмет появления там файлов, например, он должен держать коннект с другой прогой и тд. В общем этот поток должен работать пока работает основной (про основной томкат не будем, итак все время всторону уходим)).
25 июл 19, 10:44    [21934100]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
qasta
Member

Откуда:
Сообщений: 86
JDS
        while (true) {
            try {
                Files.write(Paths.get(filePath), text.getBytes(), StandardOpenOption.APPEND);
            } catch (IOException e) {
                System.out.println(e);
            }

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(DaemonClass.class.getName()).log(Level.SEVERE, null, ex);
                // вот тут надо было добавить выход из цикла (return или break)
            }
        }


И возможно, как реализовать правильнее?


У вас бесконечный цикл, который не заканчивается - добавил комментарий в то место, где ошибка.
Правильнее было бы написать не while (true) а while (workingFlag)
А в вызове contextDestroyed выставлять workingFlag = false и дожидаться через другой флаг того, что поток действительно завершился.

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

Не забудьте на ваши "флаги" добавить ключевое слово volatile (ну или обрамить доступ к ним методами с synchronized)
25 июл 19, 11:24    [21934141]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
Натянуты твои задачи.
Если они фоновые, то и делай отдельное приложение демон и старт, стоп.
Если нет, то нефиг молотить операционку на предмет - есть ли изменения при простом деплое.
ЛЮБОЙ СТАРТ ПРОГЕРА ДОЛЖЕН ИМЕТЬ СТОП В API.
Да и приложение может быть развернуто вообще в докере где нет файловой системы и d: и с:
JDS
String filePath = "D:\\myfile.txt";
25 июл 19, 11:33    [21934161]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
qasta
У вас бесконечный цикл
да. Но он сопротивляется.
В его API не предусмотрено СТОП))
25 июл 19, 11:34    [21934168]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp, ну елы-палы, ребят, я ж уже 4 раза сказал, что это просто пример и вопрос в другом
Про флаг это понятно.
Почему в первом случае не приходим в обработчик ondestroy, а во втором приходим)
Ну не задавал же я вопрос про флаг и натянутость задачи).
Да. Спросил, как сделать лучше, но в рамках примера (те поток шуршит все время пока жив породивший поток).
25 июл 19, 11:39    [21934171]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
qasta
А в вызове contextDestroyed
у него не вызывается. В этом вопрос.
25 июл 19, 11:39    [21934173]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp
qasta
А в вызове contextDestroyed
у него не вызывается. В этом вопрос.

Вызывается, но только во втором варианте.
Вопрос в том почему.
25 июл 19, 11:40    [21934176]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
PetroNotC Sharp
пропущено...
у него не вызывается. В этом вопрос.

Вызывается, но только во втором варианте.
Вопрос в том почему.
убери для вопроса все лишнее вместе с классом.
Вызывается?
И ссылку сюда на доки.
25 июл 19, 11:44    [21934185]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
Наворотил кода по памяти, а пртом спрашивает почему не работает.
А обычно пишут - написал, протестил. Написал, протестил.
25 июл 19, 12:01    [21934205]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp, два простых примера, отражающие суть вопроса и не по памяти, а вполне протестированы. Если бы наворотил, то притащил бы сюда весь код)
25 июл 19, 12:10    [21934220]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
qasta
Member

Откуда:
Сообщений: 86
JDS
PetroNotC Sharp
пропущено...
у него не вызывается. В этом вопрос.

Вызывается, но только во втором варианте.
Вопрос в том почему.


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

Именно для того, чтобы поток нельзя было прервать где и когда захочется (эквивалент kill -9) и убрали метод Thead.stop().
Для прерывания в "заранее оговоренных местах" используются "флаги". Я вам написал, что надо сделать.
Вы сделайте и протестируйте.
25 июл 19, 12:29    [21934236]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
отражающие суть вопроса
суть ПРОГРАММИРОВАНИЯ в ПОСЛЕДОВАТЕЛЬНЫХ шагах.
У вас из первого кода не следует второй кусок.
Нужно первый кусок - рабочий и второй с ошибкой.
25 июл 19, 12:31    [21934238]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
qasta, вот хотел же написать пример с флагом, тк понимал, что возможно народ пойдет в эту сторону, но понадеялся, что обьясню, а зря :)
Я же говорю, что и с флагом поведение ровно такое же, вопрос не в этом.

PetroNotC Sharp, второй вариант, который работает как надо был получен методом тыка, поэтому конечно второй кусок не следует из первого.
Различие в первом и втором примере очевидно, ну внутренняя суть не ясна: почему в 1 варианте не приходим в блок "финализации" сервлета.
25 июл 19, 13:12    [21934292]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS,
Ты долго будешь говорить или сделаешь то что тебя просят?
25 июл 19, 13:38    [21934337]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
Упрямому ТС
....
Есть такой бородатый анекдот: Стоит новый русский около своего мерса, грустно так. Останавливается еще один: че, типа, стоишь? Да вот, сломалась — не едет. А стекла протирал? Протирал. А колеса пинал? Пинал. Ну тогда, братан, не знаю. Так вот, насчет "пинал". Дело было зимой. Было достаточно холодно. Бухгалтер нашей фирмы предложил подвезти меня до метро. Надо заметить, что бухгалтер он был классный, а вот в машинах разбирался весьма и весьма слабо. Завелись, прогрелись. Пытается тронуться — машины не едет. Не буксует, а именно не едет — колеса не крутятся. Минут через двадцать стараний из офиса нами обессилившими и замерзшими был вызван в помощь другой наш сотрудник Алексей, который с машиной, что называется "на ты". Что, говорит, машину сегодня мыл? Ну, мыл. Далее Алексей со всей силы бьет ногой по колесам. И, о чудо, машина трогается. Колеса-то после мойки примерзли. Так что в каждой шутке есть доля шутки. anekdotov.net
25 июл 19, 13:40    [21934338]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp
JDS,
Ты долго будешь говорить или сделаешь то что тебя просят?

Пока, все что вижу, это: попробуй сделать с флагом, тк у тебя нет выхода из цикла.
Еще упоминание про доку, но что именно не ясно.
25 июл 19, 13:49    [21934350]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS,
Ну Иван, Иваныч!
21934185
25 июл 19, 13:54    [21934356]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
доку
естественно на событие.
25 июл 19, 13:56    [21934360]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
PetroNotC Sharp
JDS
доку
естественно на событие.

Ок, вечером поищу.
25 июл 19, 14:03    [21934369]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 2149
JDS
PetroNotC Sharp
пропущено...
естественно на событие.

Ок, вечером поищу.
ok.
Логирование без потока.
Логи сюда.
Доки сюда.
И потом частями вставляем твой поток.
25 июл 19, 14:30    [21934396]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
qasta
Member

Откуда:
Сообщений: 86
JDS
qasta, вот хотел же написать пример с флагом, тк понимал, что возможно народ пойдет в эту сторону, но понадеялся, что обьясню, а зря :)
Я же говорю, что и с флагом поведение ровно такое же, вопрос не в этом.

В чем у вас вопрос? На "Но хотелось бы понять, в чем фишка?" вам уже ответили - у вас в первом коде из цикла выхода нет.
На "как реализовать правильнее?" - вроде тоже ответили (через флаги с volatile & synchronized в простом варианте, через классы из java.util.concurrent - в сложном)...
25 июл 19, 14:40    [21934409]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
JDS
Member

Откуда:
Сообщений: 651
Все оказались правы как обычно.
Не стал разбираться почему второй вариант работает, так как выглядит криво.
А первый вариант действительно не работал так как если делать interrupt, когда поток спит, он падает на исключении "sleep interrupted" и из цикла не выходит, то есть помимо обработки исключения, туда надо втыкать break например.
При этом даже с флагом ситуация не сильно спасает, если нет выхода из цикла в catch sleep-а, а мы выставляем флаг и тут же делаем interrupt. Вот если сначала выставить флаг, потом подождать больше чем слип внутри, то можно делать интеррапт, но смысла уже нет, т.к. из цикла итак вышли нормальным образом. Про синхронайзд, как понимаю, актуально, если переменную могут менять несколько потоков одновременно, но на вс случай можно воткнуть )
25 июл 19, 21:43    [21934843]     Ответить | Цитировать Сообщить модератору
 Re: Корректное закрытие потоков.  [new]
qasta
Member

Откуда:
Сообщений: 86
JDS
Про синхронайзд, как понимаю, актуально, если переменную могут менять несколько потоков одновременно, но на вс случай можно воткнуть )

Не только "меняют", но и "читают". То есть даже если переменную меняет только один поток, а читает другой - нужен synchronized или volatile. Иначе то будет работать, то не будет (самый неприятный вид ошибок).
26 июл 19, 12:53    [21935273]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: 1 2      [все]
Все форумы / Java Ответить