当我在程序中调用java.lang.IllegalThreadStateException: Thread already started
方法第二次时,以下代码会显示start()
。
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
这会在第二时间updateUI.start()
被调用时发生。我已经多次执行它并调用该线程并在点击updateUI.start()
之前完成运行完成。
调用updateUI.run()
可以避免错误,但会导致线程在UI线程中运行(调用线程,如SO上的其他帖子中所述),这不是我想要的。
线程只能启动一次吗?如果我想再次运行该线程怎么办?这个特定的线程在后台进行一些计算,如果我不在线程中执行它而不是在UI线程中完成,并且用户有一个不合理的漫长等待。
答案 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(未知来源) * /
答案 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并将其发布在Handler的HandlerThread上。您可以提交多个Runnable
个对象。如果想要使用Runnable
run()
方法将数据发送回UI主题,请在{1}}的用户界面帖子Message
上发布Handler
并处理handleMessage
< / p>
请参阅此帖子以获取示例代码:
答案 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()方法。所以要避免它,除非你真的知道它会导致什么副作用。