在同一个线程上调用start方法两次是否合法?

时间:2009-08-01 01:15:39

标签: java android multithreading

当我在程序中调用java.lang.IllegalThreadStateException: Thread already started方法第二次时,以下代码会显示start()

updateUI.join();    

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

这会在第二时间updateUI.start()被调用时发生。我已经多次执行它并调用该线程并在点击updateUI.start()之前完成运行完成。

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

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

11 个答案:

答案 0 :(得分:107)

来自Java API Specification方法的Thread.start

  

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

此外:

  

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

是的,Thread只能启动一次。

  

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

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

答案 1 :(得分:13)

完全正确。 From the documentation

  

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

就重复计算可以做什么而言,似乎可以使用SwingUtilities invokeLater method。您已经在尝试直接调用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标记。与Android工作中的invokeLater相同的是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

答案 2 :(得分:3)

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

  

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

转储您自己的主题并使用AsyncTask

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

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

答案 3 :(得分:3)

没有,我们无法再次启动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,方法已完成。线程中的异常   "主" java.lang.IllegalThreadStateException       在java.lang.Thread.start(未知来源)   * /

check this

答案 4 :(得分:2)

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

答案 5 :(得分:1)

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

直接离开马的嘴:Java API Spec

  

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

  

线程只能启动一次吗?

是。你可以开始一次。

  

如果我想再次运行该线程怎么办?这个特定的线程在后台进行一些计算,如果我不在线程中进行,那么它在UI线程和用户有一个不合理的漫长等待。

不要再次运行Thread。而是创建Runnable并将其发布在HandlerHandlerThread上。您可以提交多个Runnable个对象。如果想要使用Runnable run()方法将数据发送回UI主题,请在{1}}的用户界面帖子Message上发布Handler并处理handleMessage < / p>

请参阅此帖子以获取示例代码:

Android: Toast in a thread

答案 9 :(得分:0)

我不知道这是否是一个好习惯,但是当我在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();
}

希望这会有所帮助,即使只是一点点。

欢呼

答案 10 :(得分:-1)

  

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

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