Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Корректное закрытие потоков.  [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]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Java Ответить