java - 在同一个线程上调用start方法两次是合法的吗?

当我在程序中第二次调用updateUI.start()方法时,以下代码导致updateUI.run()

updateUI.join();    

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

这是第二次调用updateUI.run()时发生的。 我已经多次执行它并且调用线程并且在完成updateUI.start()之前完成运行完成。

调用updateUI.run()可以避免错误,但会导致线程在UI线程(调用线程,如SO上的其他帖子中提到)中运行,这不是我想要的。

线程只能启动一次吗? 如果我想再次运行该线程怎么办? 这个特定的线程在后台进行一些计算,如果我不在线程中执行它而不是在UI线程中完成,并且用户有一个不合理的漫长等待。

Will asked 2019-09-11T05:19:16Z
10个解决方案
107 votes

Thread方法的Java API规范:

启动一个线程永远不合法   不止一次。 特别是,a   一旦线程可能无法重新启动   已完成执行。

此外:

抛出:
Thread - 如果线程已经启动。

所以是的,Thread只能启动一次。

如果是这样,如果我愿意,我该怎么做   再次运行线程?

如果需要多次运行Thread,则应该创建Thread的新实例并在其上调用start

coobird answered 2019-09-11T05:20:20Z
13 votes

非常正确。 从文档:

启动一个线程永远不合法   不止一次。 特别是,a   一旦线程可能无法重新启动   已完成执行。

就重复计算可以做什么而言,似乎可以使用SwingUtilities invokeLater方法。 您已经在尝试直接调用Swingutilities.invokeLater,这意味着您已经在考虑使用Handler而不是原始Thread。尝试在Runnable任务上使用invokeLater方法,看看它是否更符合您的心理模式。

以下是文档中的示例:

 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.");

如果用计算替换Swingutilities.invokeLater调用,它可能正是您所需要的。

编辑:跟进评论,我没有注意到原帖中的Android标记。 相当于Android工作中的invokeLater是Swingutilities.invokeLater.来自它的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

Bob Cross answered 2019-09-11T05:21:23Z
3 votes

刚到的答案涵盖了为什么你不应该做你正在做的事情。 以下是解决实际问题的一些选项。

这个特定的线程正在做一些   在后台计算,如果我   不要在线程中执行它而不是它   在UI线程中完成并且用户具有   一段不合理的漫长等待。

转储您自己的线程并使用LinkedBlockingQueue

或者在需要时创建一个新线程。

或者将线程设置为在工作队列(例如,LinkedBlockingQueue)之外操作,而不是重新启动线程。

CommonsWare answered 2019-09-11T05:22:16Z
3 votes

不,我们无法再次启动Thread,这样做会抛出runtimeException java.lang.IllegalThreadStateException。>

原因是一旦run()方法被Thread执行,它就进入死状态。

我们举一个例子 - 考虑再次启动线程并在其上调用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
    }

}

/ *在run()方法中输出OUTPUT,方法已完成。 线程中的异常   “main”java.lang.IllegalThreadStateException       在java.lang.Thread.start(未知来源)  */

检查一下

Sameer Kazi answered 2019-09-11T05:23:11Z
2 votes

你应该做的是创建一个Runnable,并在每次要运行Runnable时用新线程包装它。这样做真的很难看,但是你可以用另一个线程包装一个线程来再次运行它的代码,但这只是你必须这样做。

Peter Lawrey answered 2019-09-11T05:23:38Z
1 votes

正如你所说,一个线程不能多次启动。

直接来自马口:Java API Spec

启动一个线程永远不合法   不止一次。 特别是,a   一旦线程可能无法重新启动   已完成执行。

如果你需要重新运行你的线程中发生的任何事情,你将不得不创建一个新线程并运行它。

alanlcode answered 2019-09-11T05:24:20Z
0 votes

重用线程是Java API中的非法操作。但是,您可以将其包装到可运行的实现中,然后再次重新运行该实例。

Aaron He answered 2019-09-11T05:24:48Z
0 votes

是的,我们无法启动已经运行的线程。如果线程已经启动,它将在运行时抛出IllegalThreadStateException。

如果你真的需要启动线程怎么办:选项1)如果一个线程需要多次运行,那么应该创建一个新的Thread实例并在其上调用start。

riteeka answered 2019-09-11T05:25:22Z
0 votes

线程只能启动一次吗?

是。 你可以开始一次。

如果我想再次运行该线程,我该怎么做?这个特定的线程在后台进行一些计算,如果我不在线程中执行它而不是在UI线程中完成并且用户有一个不合理的 漫长的等待。

不要再次运行Thread。 而是创建Runnable并将其发布在HandlerThread的Handler上。 您可以提交多个Runnable个对象。 如果想要将数据发送回UI线程,请使用Runnable run()方法,在Handler的UI线程上发布Message并处理handleMessage

有关示例代码,请参阅此帖子:

Android:在线程中敬酒

Ravindra babu answered 2019-09-11T05:26:24Z
-1 votes

这样做真的很难看,但是你可以用另一个线程包装一个线程来再次运行它的代码,但这只是你必须这样做。

我不得不修复由创建Thread但没有start()的程序员引起的资源泄漏,他直接调用了run()方法。 所以要避免它,除非你真的知道它会导致什么副作用。

Torben answered 2019-09-11T05:26:59Z
translate from https://stackoverflow.com:/questions/1215548/is-it-legal-to-call-the-start-method-twice-on-the-same-thread