Законно ли вызывать метод start дважды в одном потоке? - PullRequest
86 голосов
/ 01 августа 2009

Следующий код приводит к java.lang.IllegalThreadStateException: Thread already started, когда я вызываю start() метод второй раз в программе.

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

Это происходит, когда секунда время updateUI.start() вызывается. Я прошел через это несколько раз, и поток вызывается и полностью завершается, прежде чем нажать updateUI.start().

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

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

Ответы [ 10 ]

107 голосов
/ 01 августа 2009

Из Java API Спецификации для Thread.start метода:

Нельзя начинать тему больше чем единожды. В частности, поток не может быть перезапущен, как только он завершил выполнение.

Кроме того:

Выдает:
IllegalThreadStateException - если поток уже запущен.

Так что да, Thread можно запустить только один раз.

Если да, то что мне делать, если я хочу снова запустить поток?

Если Thread нужно запускать более одного раза, нужно создать новый экземпляр Thread и вызвать на нем start.

13 голосов
/ 01 августа 2009

Совершенно верно. Из документации :

Нельзя начинать тему больше чем единожды. В частности, поток не может быть перезапущен, как только он завершил выполнение.

С точки зрения того, что вы можете сделать для повторных вычислений, кажется, что вы можете использовать SwingUtilities, метод invokeLater . Вы уже экспериментируете с непосредственным вызовом run(), то есть вы уже думаете об использовании Runnable вместо необработанного Thread. Попробуйте использовать метод invokeLater только для задачи Runnable и посмотрите, подходит ли он вашему ментальному образцу немного лучше.

Вот пример из документации:

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

Если вы замените этот вызов println своими вычислениями, это может быть именно то, что вам нужно.

РЕДАКТИРОВАТЬ: после комментария я не заметил тег Android в оригинальном сообщении. Эквивалентом invokeLater в работе Android является Handler.post(Runnable). Из его Javadoc:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

Итак, в мире Android вы можете использовать тот же пример, что и выше, заменив Swingutilities.invokeLater соответствующим постом на Handler.

3 голосов
/ 03 марта 2016

Нет , мы не можем запустить Thread снова, это вызовет исключение runtimeException java.lang.IllegalThreadStateException. >

Причина в том, что метод run () выполняется потоком, и он переходит в мертвое состояние.

Давайте рассмотрим пример. Думать о том, чтобы снова запустить поток, и вызвать для него метод start () (который внутренне будет вызывать метод run ()) - это то же самое, что попросить мертвого человека проснуться и запустить Как и после завершения своей жизни человек переходит в мертвое состояние.

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * OUTPUT в методе run (), метод завершен. Исключение в потоке "основной" java.lang.IllegalThreadStateException на java.lang.Thread.start (неизвестный источник) * /

отметьте это

3 голосов
/ 01 августа 2009

Только что пришедший ответ объясняет, почему вы не должны делать то, что делаете. Вот несколько вариантов решения вашей актуальной проблемы.

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

Создайте свою собственную ветку и используйте AsyncTask.

Или создайте новую ветку, когда вам это нужно.

Или настройте поток для работы вне рабочей очереди (например, LinkedBlockingQueue) вместо перезапуска потока.

2 голосов
/ 01 августа 2009

Что вам нужно сделать, это создать Runnable и оборачивать его новым потоком каждый раз, когда вы хотите запустить Runnable. Это было бы очень уродливо, но вы можете обернуть поток другим потоком, чтобы снова запустить код для него, но только если это действительно так.

1 голос
/ 01 августа 2009

Как вы сказали, поток не может быть запущен более одного раза.

Прямо изо рта лошади: Спецификация Java API

Этоникогда не разрешено начинать тему более одного раза.В частности, поток не может быть перезапущен после завершения выполнения.

Если вам нужно перезапустить все, что происходит в вашем потоке, вам придется создать новый поток и запустить его.

0 голосов
/ 30 августа 2017

Может ли поток быть запущен только один раз?

Да. Вы можете начать его ровно один раз.

Если да, то что мне делать, если я хочу снова запустить поток? Этот конкретный поток выполняет некоторые вычисления в фоновом режиме, если я не делаю это в потоке, чем это делается в потоке пользовательского интерфейса и пользователя имеет необоснованно долгое ожидание.

Не запускайте Thread снова. Вместо этого создайте Runnable и опубликуйте его на Handler из HandlerThread . Вы можете отправить несколько Runnable объектов. Если вы хотите отправить данные обратно в поток пользовательского интерфейса, используя метод Runnable run(), отправьте Message в Handler потока пользовательского интерфейса и обработайте handleMessage

Обратитесь к этому сообщению, например, код:

Android: тост в потоке

0 голосов
/ 25 июля 2017

Да, мы не можем запустить уже запущенный поток. Он выдаст исключение IllegalThreadStateException во время выполнения - если поток уже запущен.

Что, если вам действительно нужно запустить тему: Вариант 1) Если поток нужно запускать более одного раза, нужно создать новый экземпляр потока и запустить его.

0 голосов
/ 15 августа 2013

Повторное использование потока является недопустимым действием в Java API. Однако вы могли бы обернуть его в работающий агрегат и снова запустить этот экземпляр.

0 голосов
/ 15 ноября 2011

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

Мне пришлось исправить утечку ресурсов, вызванную программистом, который создал поток, но вместо запуска () он вызвал метод run () - напрямую. Поэтому избегайте этого, если только вы действительно не знаете, какие побочные эффекты это вызывает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...