为啥不在构造函数中启动一个线程?如何终止?
Posted
技术标签:
【中文标题】为啥不在构造函数中启动一个线程?如何终止?【英文标题】:Why not to start a thread in the constructor? How to terminate?为什么不在构造函数中启动一个线程?如何终止? 【发布时间】:2011-08-03 03:46:01 【问题描述】:我正在学习如何在 Java 中使用线程。我编写了一个实现 Runnable 以同时运行到另一个线程的类。主线程负责监听串行端口,而第二个线程负责将数据发送到同一个端口。
public class MyNewThread implements Runnable
Thread t;
MyNewThread()
t = new Thread (this, "Data Thread");
t.start();
public void run()
// New Thread code here
第一个线程像这样开始第二个线程:
public class Main
public static void main(String[] args) throws Exception
new MyNewThread();
// First thread code there
这可行,但我的编译器标记了一条警告:在构造函数中启动新线程很危险。这是为什么呢?
这个问题的第二部分是:如果我在一个线程(串行端口侦听线程)中运行一个循环并且我在我的第二个线程中键入退出命令。如何让第一个线程终止?谢谢。
【问题讨论】:
最好将问题的第二部分分叉到另一个线程中,呃,我的意思是,问题。 考虑为问题的第二部分询问实际的第二个 *** 问题。这将为您提供每个问题的最佳答案。 第一个问题在这里得到了回答:***.com/questions/84285/…。由于第二部分,我不会投票关闭作为重复...现在这变得复杂,因为已经有答案:( 【参考方案1】:对于您的第一个问题:在传入this
的构造函数中启动线程转义this
。这意味着您实际上是在对象完全构造之前给出了对它的引用。该线程将在您的构造函数完成之前启动。这可能会导致各种奇怪的行为。
关于您的第二个问题:在 Java 中没有可接受的强制另一个线程停止的方法,因此您将使用一个变量,该线程将检查它是否应该停止。另一个线程将设置它以指示第一个线程将停止。该变量必须是易失的或所有访问同步以确保正确发布。这里有一些你想要的代码。
public class MyNewThread implements Runnable
private final Thread t;
private volatile boolean shouldStop = false;
MyNewThread()
t = new Thread (this, "Data Thread");
public void start()
t.start();
public void stop()
shouldStop = true;
public void run()
while(!shouldStop)
// do stuff
只要想创建和启动线程就行:
MyNewThread thread = new MyNewThread();
thread.start();
任何想停止线程都会做的事情:
thread.stop();
【讨论】:
在构造函数中启动线程只有在您实际发布 this 时才会发布 this(如上面的代码中所示,即便如此,发布的还是构造函数调用)。foo = new SomeSpecialThread(); foo.start();
没有发布这个,或者是吗?现在,在 它自己的 构造函数上启动一个线程确实会暴露一个不完整的对象。
@seh:不需要,因为对它的所有访问都是同步的。 @Justin:从Thread
继承不是更好吗?
@Justin,“要使用不同步的 volatile,您需要确保只有一个线程会修改它,而这里不是这种情况。” ……这是错误的。对 volatile 变量的更改对其他线程可见,无需进一步同步。写入一个 volatile 变量并随后读取相同的变量会创建“先发生”关系,这保证在 Java 内存模型中是可见的。有关详细信息(或 JMM 规范),请参阅 download.oracle.com/javase/6/docs/api/java/util/concurrent/…。
@Peter 您当然是对的,我误读了 JCIP 中的声明。只有当写入变量确实取决于其当前值时,您必须确保只有一个线程正在更新值
@shareef:你在这里看到的.stop()
不是来自java.lang.Thread
的那个,而是一个独立的。虽然名称对 start
和 stop
非常好,但您说得对,它不应该在 Java 线程的上下文中使用,因为它看起来像被禁止的 Thread.stop()
方法。【参考方案2】:
让我们看一个基本的例子:
class MyClass implements Runnable
int a = 0;
String b = null;
public MyClass()
new Thread(this).start();
b = "Foo";
public void run()
a = b.length(); //can throw NullPointerException
在这种情况下,MyClass.this 被称为 escape 构造函数。这意味着该对象可用于引用,但可能不会创建在构造函数中构建的所有字段。如果 b 是final
将其提升到另一个层次,您会期望它可用,但不能保证。这被称为部分构造的对象,在 java 中是完全合法的。
【讨论】:
【参考方案3】:关于第二个问题,
您可以通过isAlive
方法检查第二个线程是否已终止,如果是,则使用break
关键字关闭第一个线程的循环,然后如果无事可做将被终止
public class MyNewThread implements Runnable
Thread t;
MyNewThread()
t = new Thread (this, "Data Thread");
t.start();
public void run()
reading code ................
// New Thread code here
public class Main
public static void main(String[] args) throws Exception
MyNewThread thread = new MyNewThread();
while(true)
listening code ...................
if(!thread.t.isAlive())
break;
【讨论】:
即使在类构造函数中启动和启动线程的稳定性值得怀疑,执行 myClass.isAlive() 检查的建议也不是让 main() 方法等待而类线程运行。它应该在带有睡眠暂停的 while 循环中调用,包含在 try/catch 块中,寻找 InterruptedException。【参考方案4】:这个问题的第二部分是: 如果我有一个循环运行在一个 thread(串口监听线程) 我在我的 第二个线程。我如何获得第一 线程要终止?
让它一直循环直到达到一个条件。例如:
public void run()
while ( !inputConsole.getCommand().equals("exit") )
//Do Something
Thread.sleep(1000); //put thread to sleep for 1 second
【讨论】:
以上是关于为啥不在构造函数中启动一个线程?如何终止?的主要内容,如果未能解决你的问题,请参考以下文章
当 MainWindow 从另一个类(不在主函数中)启动时,QT ui 未显示