Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Как остановить Thread?


Автор: Aehn 13.5.2008, 14:27
Есть класс myThread - наследник Thread
Запускаю его нормально, а вот чтобы остановить вызываю
myClass.stop()
на что компилятор ругается
Код

    public void stop()
    {
        if(myThread != null)
        {
           myThread.stop();
           myThread = null;
        }
    }

Но, помнится, когда-то давно этот пример нормально шел.
Так как его надежно остановить?

Добавлено через 4 минуты и 54 секунды
Все, вопрос  решился. Есть метод interrupt()

Автор: $tatic 13.5.2008, 14:59
Aehn,
вообще-то это неправильно, документация предлагает сделать вот так:

было
Код

    private Thread blinker;

    public void start() {
        blinker = new Thread(this);
        blinker.start();
    }

    public void stop() {
        blinker.stop();  // UNSAFE!
    }

    public void run() {
        Thread thisThread = Thread.currentThread();
        while (true) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            repaint();
        }
    }


стало
Код

    private volatile Thread blinker;

    public void stop() {
        blinker = null;
    }

    public void run() {
        Thread thisThread = Thread.currentThread();
        while (blinker == thisThread) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            repaint();
        }
    }

Автор: Дрон 26.5.2008, 09:44
Подниму тему. Что-то я так и не понял, как нормально прервать поток, раз stop() теперь deprecated?

У меня есть поток, который в фоновом режиме загружает из JPEG большую картинку (например 80 мегапикселей). Такая картинка занимает порядка 500 мегабайт в памяти и загружается около 7 секунд.

Если вдруг на середине загрузки я узнал, что мне эта картинка не нужна, а нужна другая, то как мне прервать поток?
Метод interrupt() не подходит, так как он не прерывает поток, а только выставляет соответствующий статус потока, который я не могу проверить пока картинка полностью не загрузится. А если вторая картинка тоже на 500 мегабайт, то обе сразу в память могут и не поместиться.

Что делать?

Автор: Hidrag 26.5.2008, 10:06
Намудрили то smile Куда все проще!

Как вариант:
1. Создаем класс, наследуем его от Thread.
2. В этом классе создаем паблик переменную логического типа.
3. В методе run этого класса определяем место или места где смотрим эту переменную и если она истина (или ложь, смотря как спрограммировать) то делаем break или return опять же в зависимости от того что делается в этом методе.
4. В классе откуда будет запускаться поток создаем объект выше созданного класса.
5. Вызываем у него метод start() - все поток запущен!
6. Если нужно "убить поток" у созданного объекта потока меняем логическую переменную, в потоке эта переменная проверится там где мы ее ранее определили и поток остановится.

Что то вроде такого, все просто! Особенно удобно если в потоке крутится какой то цикл.

Автор: Platon 26.5.2008, 10:35
Hidrag, между прочим, Дрон не намудрил, он работает с interrupt, и на мой взгляд это куда правильней, чем плодить доп. логические переменные.

Случай, конечно, интересный. Я так же задавался вопросом, как можно без всяких проверок рубануть поток?
Таким образом нам нужно писать потокозависимые компоненты, т.е. к примеру загрузчик изображения из сети, который каждые N байтов проверяет, актуальна ли еще его загрузка.

Автор: Hidrag 26.5.2008, 11:49
Цитата(Platon @  26.5.2008,  10:35 Найти цитируемый пост)
Таким образом нам нужно писать потокозависимые компоненты, т.е. к примеру загрузчик изображения из сети, который каждые N байтов проверяет, актуальна ли еще его загрузка. 


и


Цитата(Hidrag @  26.5.2008,  10:06 Найти цитируемый пост)
3. В методе run этого класса определяем место или места где смотрим эту переменную и если она истина (или ложь, смотря как спрограммировать) то делаем break или return опять же в зависимости от того что делается в этом методе.


Тоже самое и получается smile ты предлагаешь проверять актуальность, а я предложил в качестве актуальности булеву переменную smile а break, return или загрузка новой картинки зависит от задачи )

Автор: Дрон 26.5.2008, 12:03
Цитата(Hidrag @  26.5.2008,  10:06 Найти цитируемый пост)
Особенно удобно если в потоке крутится какой то цикл.

Меня интересует мой конкретный случай. Общие подходы я отлично знаю, но вот в моём случае они не работают. В моём потоке и цикла никакого нет, упрощённо говоря он вообще состоит из вызова одного единственного метода из ImageIO, загружающего картинку.

Цитата(Platon @  26.5.2008,  10:35 Найти цитируемый пост)
Таким образом нам нужно писать потокозависимые компоненты, т.е. к примеру загрузчик изображения из сети, который каждые N байтов проверяет, актуальна ли еще его загрузка. 

О том и речь :(
Я предполагаю, что можно грузить картинку по частям (tiles), разбив её на прямоугольники размером в пару-тройку мегапикселей и потом собирать в одну большую... Но мне кажется, что помимо усложнения кода, это потребует дополнительного времени на обработку и увеличит расход памяти, так что в данном случае проще вызвать Thread.stop().

Ведь то, что он deprecated не означает, что он не работает? Или есть шанс, что потом они его вообще выкинут?

Автор: Platon 26.5.2008, 12:19
Цитата(Дрон @  26.5.2008,  13:03 Найти цитируемый пост)
Или есть шанс, что потом они его вообще выкинут?

Именно, хотя уже какую версию этот stop тянется.

Автор: Дрон 26.5.2008, 12:43
Цитата(Platon @  26.5.2008,  12:19 Найти цитируемый пост)
Именно, хотя уже какую версию этот stop тянется. 

Эх... Хотя думаю, что всё равно не выкинут smile
Но мне, скорее всего, придётся всё-таки по кускам картинку грузить, благо все соответствующие методы для этого есть.
Главное, чтобы на быстродействие и память это не сильно влияло.

Автор: Maksym 26.5.2008, 17:07
Дрон
Думаю, нужно грузить картинку не метдами ImageIO, а каким-нибудь простым байтовым стримом, где ты в цикле выбирашь данные в буфер. Там есть возможность сделать любую проверку на каждой итерации и прерваться при необходимости. А потом, после окончания загрузки, целиком загруженные данные можно отдать в более высокоуровневые методы из ImageIO.

Автор: Дрон 26.5.2008, 17:15
Цитата(Maksym @  26.5.2008,  17:07 Найти цитируемый пост)
Думаю, нужно грузить картинку не метдами ImageIO, а каким-нибудь простым байтовым стримом, где ты в цикле выбирашь данные в буфер. Там есть возможность сделать любую проверку на каждой итерации и прерваться при необходимости. А потом, после окончания загрузки, целиком загруженные данные можно отдать в более высокоуровневые методы из ImageIO.

Там JPEG. Сам файл занимает, скажем, порядка 20-30 мегабайт и загрузить его в память -- один миг, проблема состоит в декодировании JPEG, которое и занимает основное время. Писать собственный декодер я пока не готов -- и так времени нет smile

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

Автор: math64 27.5.2008, 13:17
Код

class StopException extends RuntimeException {}
intreface StopChecker {
  void stopCheck() throws StopException;
}
class StopCheckInputStream extends InputSteam {
  StopChecker checker;
  void setChecker(StopChecker checker) {
    this.checker = checker;
  }
  ...
  int read (...) {
    if (checker != null) checker.stopCheck();
    return super.read(...);
  }
  ...
}

class LoadImageThread extends Thread {
   BufferedImage image;
   void run() {
      try {
         StopCheckerInputStream is = new StopCheckerInputStream(...);
         is.setChecker(new StopChecker() { ... });
         image = ImageIO.read(is);
      } catch (StopException ex) {
         image = null;
      } 
   }
}

Автор: Дрон 27.5.2008, 13:47
math64, это вроде не совсем то. Но в общем случае -- да, можно было использовать перегруженный InputStream, при условии что декодирование идёт вместе с чтением. А вот если сначала читается весь файл, а только потом декодируется, то этот способ не пойдёт -- как внутри устроен ImageIO я не знаю.

Свою проблему я решил даже проще -- как оказалось ImageReader из ImageIO умеет сообщать свой прогресс, и вот в обрабочик прогресса я и добавил проверку на то не был ли прерван поток.

Так что с потоками пока разобрался. Всем отвечавшим спасибо smile

Автор: COVD 27.5.2008, 17:04
Цитата

Hidrag, между прочим, Дрон не намудрил, он работает с interrupt, и на мой взгляд это куда правильней, чем плодить доп. логические переменные.


interrupt по моему представлению, прерывает не выполнение потока, а ожидание. Если поток стоит в wait(), то interrupt() его разбудит. Если же поток выполняет последовательность команд, например, вычисления в цикле, то  interrupt()  никакого эффекта не даст - у потока нет никакого внутреннего флага, который он бы проверял на каждом шагу. Это дело программиста - "плодить доп. логические переменные", если надо. И это компетенция программиста ставить проверку флага в правильном месте: например, поток открыл соединение, потом проверил флаг, и обнаружил команду  "умереть". Так перед смертью он должен открытое соединение закрыть. Освободить захваченные ресурсы.

Автор: Дрон 27.5.2008, 18:02
Цитата(COVD @  27.5.2008,  17:04 Найти цитируемый пост)
interrupt по моему представлению, прерывает не выполнение потока, а ожидание. Если поток стоит в wait(), то interrupt() его разбудит. Если же поток выполняет последовательность команд, например, вычисления в цикле, то  interrupt()  никакого эффекта не даст - у потока нет никакого внутреннего флага, который он бы проверял на каждом шагу.

Использование interrupt() избавляет от необходимости вводить дополнительную булевую переменную, потому что у потока есть метод isInterrupted() позволяющий проверить, требуется ли прервать выполнение.

Автор: mindflyer 28.5.2008, 11:47
Цитата(Дрон @  27.5.2008,  18:02 Найти цитируемый пост)
Использование interrupt() избавляет от необходимости вводить дополнительную булевую переменную, потому что у потока есть метод isInterrupted() позволяющий проверить, требуется ли прервать выполнение.

Иногда лучше всё же добавлять свою переменную. Уже писал где-то на форуме - столкнулся с ситуацией, когда interrupt перехватывался в сторонней библиотеке, обрабатывался и сбрасывался флаг. В итоге, если interrupt был вызван, когда управление было не в моём коде, а в коде той библиотеки, то мой код вызывая inInterrupted() получал false и продолжал выполнение.

Автор: Дрон 28.5.2008, 12:27
Цитата(mindflyer @  28.5.2008,  11:47 Найти цитируемый пост)
Уже писал где-то на форуме - столкнулся с ситуацией, когда interrupt перехватывался в сторонней библиотеке, обрабатывался и сбрасывался флаг.

Хм. А вот это действительно возможно.

Автор: COVD 28.5.2008, 15:49
Цитата(Дрон @ 27.5.2008,  18:02)
..потому что у потока есть метод isInterrupted() ..

Спасибо, совсем забыл.

Цитата

столкнулся с ситуацией, когда interrupt перехватывался в сторонней библиотеке, обрабатывался и сбрасывался флаг


Это просто вредительство smile.  А как это возможно - сбросить флаг? У потока вроде нет метода setInterrupted. Как можно разентерраптить?

Автор: AlexeyVorotnikov 28.5.2008, 16:39
Цитата(COVD @ 28.5.2008,  16:49)
Цитата(Дрон @ 27.5.2008,  18:02)
..потому что у потока есть метод isInterrupted() ..

Спасибо, совсем забыл.

Цитата

столкнулся с ситуацией, когда interrupt перехватывался в сторонней библиотеке, обрабатывался и сбрасывался флаг


Это просто вредительство smile.  А как это возможно - сбросить флаг? У потока вроде нет метода setInterrupted. Как можно разентерраптить?

У потока так же есть метод
public static boolean interrupted()
в описании которого сказано:
Цитата

Tests whether the current thread has been interrupted. The interrupted status of the thread is cleared by this method. In other words, if this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it).

Автор: COVD 28.5.2008, 17:14
 smile 

Спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)