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


Автор: _Y_ 25.1.2007, 21:39
Предистория:  В главном потоке вызывается метод. Этот метод делает вычисления и возвращает значение. Выяснилось, что дело медленное и надо показывать прогресс монитор, а для этого вычисления выносить в отдельный Thread.

Проблема: После вывода в отдельную Thread возникли сложности с возвратом значения. Попробовал решить так. В классе-наследнике Thread завел переменную valueResult, в которую должен этот самый результат быть записон после окончания работы метода run():
Код

private class ThreadCalculate extends Thread {
    public int valueResult;
.......
    public void run(){
        .........
        valueResult = something;
    }
}

Но встала проблема: как дождаться окончания работы Thread, чтобы эту переменную прочитать?
Попробовал сделать так (нарыл что-то подобное в сети и модифицировал):            
Код

ThreadCalculate threadCalculate = new ThreadCalculate();
threadCalculatePvalues.start();
try {
    do {
        threadCalculatePvalues.join(100);
        threadCalculatePvalues.sleep(100);
    } while(threadCalculatePvalues.isAlive());
} catch (InterruptedException e) {}
return threadCalculate.valueResult;

Подвисает GUI, а если убираю блок try-catch со всем содержимым, то, естественно, значение threadCalculate.valueResult читается до того, как закончился рассчет smile 

Эпилог: Понимаю, что изначально надо было делать структуру программы с рассчетом на многопоточность, не бейте. Сейчас переделывать уже будет слишком много. Можно ли как то решить?
 

Автор: s8e8r8g8e 25.1.2007, 22:04
ну да подвисает...
вычислитнельный поток замораживается на 100 мсек.. почти сразу за этим основной поток ждёт 100 мсек а не закончится ли вычислительный.. после чего отправляет его опять спать, этак он никогда и не работает кроме как первые 100 мсек smile, а значит и основой никогда из цикла не выйдет..
а где здесь прогрессбар апдейтится?

Автор: _Y_ 25.1.2007, 23:48
Цитата(s8e8r8g8e @ 25.1.2007,  22:04)
ну да подвисает...
... этак он никогда и не работает кроме как первые 100 мсек smile, а значит и основой никогда из цикла не выйдет..
а где здесь прогрессбар апдейтится?

Я и сам вижу что фигня это. Но как сделать не знаю.  А прогрессбар апгрейдится внутри метода run(), но это не важно, прогрессбар может быть и indeterminate. Он все равно подвисает вместе с GUI smile 

Автор: shimopus 26.1.2007, 00:08
Предлагаю проверять живость потока, который в свою очередь после того как посчитает значение переменной запишет либо в общедоступный класс, либо дернет метод главного потока.

Код

 do 
{
        
} 
while(threadCalculatePvalues.isAlive());
//Здесь читаем готовое значение 
//посчитанное в потоке и сохраненное 
//где-нибудь в общедоступном месте

Автор: Stampede 26.1.2007, 00:32
_Y_, ты пытаешься снаружи опрашивать состояние вычислительного потока, и от этого все твои трудности. На самом деле проблема решается выворачиванием ролей наизнанку: визуальный компонент регистрируется слушателем событий твоего потока, а поток уже по достижении определенных состояний/контрольных точек вызывает методы слушателя. Вот как это может выглядеть на Java.

Описываем интерфейс слушателя:

Код

public interface ProgressListener {
  public void jobStarted();
  public void completed(int percentage);
  public void jobDone();
}


В классе-потоке делаем так:

Код

public class Calculation implements Runnable {
  private ProgressListener listener;

  public void setProgressListener(ProgressListener listener) {
    this.listener = listener;
  }

  public void run() {
    listener.jobStarted();

    for (int = 0; i < 100; i++) {
      // do some calculation
      listener.completed(i + 1);
    }

    listener.jobDone();
  }
}


Надеюсь, понятно, что пример упрощенный, но в целом идея примерно такая. На практике слушателей в общем случае может быть больше одного, поэтому слушателей обычно хранят в списке, а чтобы упростить вызов оповещений, дополнительно объявляют методы типа fireJobStarted(), fireJobDone() и т. д., и в них уже перебирают и в цикле дергают соответствующий метод каждого слушателя.

Где-то примерно вот так.

Автор: _Y_ 26.1.2007, 12:56
Цитата(shimopus @ 26.1.2007,  00:08)
Предлагаю проверять живость потока...
Код

 do 
{
} 
while(threadCalculatePvalues.isAlive());


И это пробовал, и с приоритетом потоков играл. Все равно перерисовка GUI подвисает smile 

Цитата(Stampede @ 26.1.2007, 00:32)
_Y_, ты пытаешься снаружи опрашивать состояние вычислительного потока, и от этого все твои трудности. На самом деле проблема решается выворачиванием ролей наизнанку...

Это я понимаю. Можно через листенеры делать, а можно, наверное, просто передать потоку ссылку на объект и в конце вычислений просто вызвать метод объекта передав параметр содержащий результат. Проблема-то в том, что этот "правильный" подход потребует серьезной переделки структуры уже работающей программы. Вот и хочется обойтись "малой кровью", т.е. заставить метод запустить поток и обождать результата, но, при этом, не блокировать GUI.

Автор: shimopus 26.1.2007, 12:59
а как ты хочешь, чтобы  GUI получило результат выполнения операции не ожидая его? Не переделывая ничего не думаю, что что-нибудь получится...

Автор: _Y_ 26.1.2007, 19:07
Цитата(shimopus @ 26.1.2007,  12:59)
а как ты хочешь, чтобы  GUI получило результат выполнения операции не ожидая его?

Да нет. Я просто хотел чтобы GUI перерисовывался не дожидаясь окончания работы метода вызвавшего Thread. Ему результат не нужен. Но, вы все, видимо, правы и Java в этом деле обману не поддается smile 

Автор: powerOn 26.1.2007, 21:23
Цитата(_Y_ @  26.1.2007,  19:07 Найти цитируемый пост)
Я просто хотел чтобы GUI перерисовывался не дожидаясь окончания работы метода вызвавшего Thread.


Нужно вынести логику в отдельный поток, иначе вы блокируете системную очередь рассылки сообщений. Пока она заблокирована интерфейс не будет перерисован. И сообщения к GUI  контролам не будут доходить. Это кстати уже где-то в GUI разделе обсуждалось.

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