Следующий код приводит к тому, java.lang.IllegalThreadStateException: Thread already started
что я вызвал start()
метод второй раз в программе.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
Такое бывает во второй раз updateUI.start()
называется. Я прошел через это несколько раз, и поток вызывается и полностью выполняется до завершения, прежде чем попасть updateUI.start()
.
Вызов updateUI.run()
позволяет избежать ошибки, но заставляет поток запускаться в потоке пользовательского интерфейса (вызывающем потоке, как упоминалось в других сообщениях на SO), чего я не хочу.
Можно ли запустить поток только один раз? Если да, то что мне делать, если я хочу снова запустить поток? Этот конкретный поток выполняет некоторые вычисления в фоновом режиме, если я не делаю этого в потоке, чем это делается в потоке пользовательского интерфейса, и у пользователя неоправданно долгое ожидание.
источник
Ответы:
Из спецификации Java API для
Thread.start
метода:Более того:
Так что да,
Thread
можно запустить только один раз.Если
Thread
необходимо запустить более одного раза, нужно создать новый экземплярThread
и вызватьstart
его.источник
Thread
каждый раз создавать новую . Вместо этого он должен отправить задачу в пул потоков (например,java.util.concurrent.ThreadPoolExecutor
)Абсолютно верно. Из документации :
С точки зрения того, что вы можете сделать для повторяющихся вычислений, кажется, что вы могли бы использовать метод SwingUtilities invokeLater . Вы уже экспериментируете с
run()
прямым вызовом , что означает, что вы уже думаете об использовании,Runnable
а не rawThread
. Попробуйте использовать этот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
.источник
RunOnUIThread(Runnable)
илиView.post(Runnable)
вместо создания собственного обработчика. Они запустят runnable в основном потоке, что позволит вам обновить пользовательский интерфейс.Только что полученный ответ объясняет, почему вам не следует делать то, что вы делаете. Вот несколько вариантов решения вашей актуальной проблемы.
Скиньте собственный поток и пользуйтесь
AsyncTask
.Или создайте новую ветку, когда вам это нужно.
Или настройте свой поток для работы вне очереди работ (например,
LinkedBlockingQueue
), а не перезапускать поток.источник
Нет , мы не можем снова запустить Thread, это вызовет исключение runtimeException java.lang.IllegalThreadStateException. >
Давайте возьмем пример. Думать о том, чтобы снова запустить поток и вызвать для него метод 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 } }
Проверь это
источник
Что вам нужно сделать, так это создать Runnable и оборачивать его новым потоком каждый раз, когда вы хотите запустить Runnable. Это было бы действительно некрасиво, но вы можете обернуть поток другим потоком, чтобы снова запустить код для него, но делать это только в том случае, если вам действительно нужно.
источник
Как вы сказали, поток не может быть запущен более одного раза.
Прямо из уст: Java API Spec
Если вам нужно повторно запустить все, что происходит в вашем потоке, вам придется создать новый поток и запустить его.
источник
Повторное использование потока является незаконным действием в Java API. Однако вы можете превратить его в работоспособный инструмент и снова запустить этот экземпляр.
источник
Да, мы не можем запустить уже работающий поток. Он вызовет исключение IllegalThreadStateException во время выполнения - если поток уже был запущен.
Что, если вам действительно нужно запустить поток: Вариант 1) Если поток нужно запускать более одного раза, то нужно создать новый экземпляр потока и вызвать на нем start.
источник
Да. Вы можете запустить его ровно один раз.
Не запускайте
Thread
снова. Вместо этого создайте Runnable и опубликуйте его в Handler of HandlerThread . Вы можете отправить несколькоRunnable
объектов. Если хотите отправить данные обратно в поток пользовательского интерфейса, с-в вашемRunnable
run()
методе, оставитьMessage
наHandler
нитки UI и процессhandleMessage
Обратитесь к этому сообщению для примера кода:
Android: тост в ветке
источник
Я не знаю, является ли это хорошей практикой, но когда я позволяю вызывать run () внутри метода run (), он не выдает ошибок и фактически делает именно то, что я хотел.
Я знаю, что он больше не запускает тему, но, возможно, это пригодится вам.
public void run() { LifeCycleComponent lifeCycleComponent = new LifeCycleComponent(); try { NetworkState firstState = lifeCycleComponent.getCurrentNetworkState(); Thread.sleep(5000); if (firstState != lifeCycleComponent.getCurrentNetworkState()) { System.out.println("{There was a NetworkState change!}"); run(); } else { run(); } } catch (SocketException | InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread checkingNetworkStates = new Thread(new LifeCycleComponent()); checkingNetworkStates.start(); }
Надеюсь, это поможет, даже если это совсем немного.
Ура
источник
Мне пришлось исправить утечку ресурсов, которая была вызвана программистом, который создал поток, но вместо start () он напрямую вызвал метод run (). Так что избегайте этого, если вы действительно не знаете, какие побочные эффекты он вызывает.
источник
run()
напрямую, а просто встроить Runnable в поток и предположительно вызватьstart()
.