Why not to start a thread in the constructor? How to terminate?
我正在学习如何在Java中使用线程。 我写了一个实现Runnable的类,以同时运行到另一个线程。 主线程处理侦听串行端口,而第二个线程将处理向该端口发送数据。
1 2 3 4 5 6 7 8 9 10 11
| public class MyNewThread implements Runnable {
Thread t ;
MyNewThread () {
t = new Thread (this, "Data Thread");
t. start();
}
public void run () {
// New Thread code here
} |
第一个线程从第二个开始,如下所示:
1 2 3 4 5 6
| public class Main {
public static void main (String[] args ) throws Exception{
new MyNewThread ();
// First thread code there
}
} |
这可行,但是我的编译器会标出警告语:在构造函数中启动新线程很危险。 为什么是这样?
这个问题的第二部分是:如何在一个线程(串行端口侦听线程)中运行循环,并在第二个线程中键入退出命令。 如何获得第一个终止的线程? 谢谢。
-
最好将问题的第二部分插入另一个线程,呃,我的意思是,问题。
-
考虑问问题的第二部分实际的第二个StackOverflow问题。 这将为您提供最佳答案。
-
在这里回答了第一个问题:stackoverflow.com/questions/84285/。 由于第二部分,我不会投票以重复形式结束...现在,由于已经有了答案,因此很难分开:((
第一个问题:在传递this的构造函数中启动线程会转义this。这意味着您实际上是在完全构造对象之前给出对对象的引用。该线程将在构造函数完成之前启动。这会导致各种奇怪的行为。
关于第二个问题:在Java中没有强制其他线程停止的方法,因此您将使用一个变量,该线程将检查该变量以知道是否应该停止。另一个线程将其设置为指示第一个线程将停止。该变量必须是易失性的,或者所有访问都必须同步,以确保正确发布。这是一些您想要的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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
}
}
} |
任何想要创建和启动线程的方法都会:
1 2
| MyNewThread thread = new MyNewThread();
thread.start(); |
想要停止线程的任何事情都会做:
-
仅当您实际发布此线程时,才在构造函数中启动线程才能发布它(如上面的代码,甚至是上面发布过程的构造函数调用一样)。 foo = new SomeSpecialThread(); foo.start();不发布此文件,还是发布?现在,在其自己的构造函数上启动线程确实确实暴露了一个不完整的对象。
-
我希望您打算使字段shouldStop易变。
-
@seh:不需要这样做,因为对它的所有访问都是同步的。 @Justin:从Thread继承会更好吗?
-
@seh使其变得不稳定是不够的。要在不同步的情况下使用volatile,您需要确保仅单个线程将对其进行修改,在此情况并非如此。
-
是的,我知道了,但是synchronized监视器的使用率过高。没有线程想等待该条件的改变。贾斯汀,是什么让您认为只有一个线程可以更改该字段?它只会经历一个过渡:从虚假到真实。将相同的易失性值从false更改为true的两个线程不会相互干扰。
-
@Martinho Fernandes:您当然可以从Thread继承,但是您可能不必要地将自己锁定在该继承路径中
-
@seh:与调用wait()/ notify()无关。它只是关于发布对象的状态。如果一个线程在变量上设置了一个值,并且该变量不是易失性的或未同步的,则它可能永远不会对其他线程可见。
-
@seh:您将来可能会对其进行修改,以使其成为状态枚举或不仅仅是true / false的内容。为什么不从一开始就使其具有前瞻性?
-
贾斯汀,我想您在这里和错误的人吵架。请阅读我再次写的内容:我建议将字段shouldStop设置为volatile,并且不要对其访问进行同步。它的唯一用途是告诉主线程循环何时停止,哪个volatile值最有效。同样,这里不需要同步。
-
@seh:我同意你的意思。我只是发现自己倾向于向事物添加诸如暂停和恢复之类的东西,并且最终不得不允许的不仅仅是简单的停止检查,但为了简单起见,我将在此处更改示例
-
@Justin,"要使用不同步的volatile,您需要确保仅单个线程将对其进行修改,在此情况并非如此。" ...这是错误的。易失变量的更改对其他线程可见,而无需进一步同步。编写一个volatile变量并随后读取相同的变量会创建" happens-before"关系,该关系在Java内存模型中保证是可见的。有关详细信息(或JMM规范),请参见download.oracle.com/javase/6/docs/api/java/util/concurrent/。
-
@Peter您当然是对的,我看错了JCIP中的声明。只有在写入变量确实取决于变量的当前值的情况下,才必须确保只有一个线程在更新该值
-
.stop()已弃用
-
@shareef:您在此处看到的.stop()不是java.lang.Thread中的那个,而是一个独立的。虽然名称对start和stop是一个非常不错的名称,但是您应该在Java线程的上下文中使用它,这是正确的,因为它看起来像被禁止的Thread.stop()方法。
让我们看一个基本的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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逃脱了构造函数。这意味着该对象可用于引用,但是可能不会创建在构造函数中构建的所有对象。如果b为final,将其提升到另一个水平,您希望它可用,但不能保证。这被称为部分构造的对象,并且在Java中完全合法。
关于第二个问题,
您可以通过isAlive方法检查第二个线程是否已终止,如果是,请使用break关键字关闭第一个线程的循环,然后在无需执行任何操作时将终止
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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()方法在类线程运行时等待也不错。应该在try / catch块中包含休眠暂停的while循环中调用它,以查找InterruptedException。
The second part to this question is:
how if I have a loop running in one
thread (the serial port listen thread)
and I type an exit command in my
second thread. How do I get the first
thread to terminate?
让它一直循环直到达到条件为止。例如:
1 2 3 4 5 6
| public void run () {
while ( !inputConsole. getCommand(). equals("exit") ) {
//Do Something
Thread. sleep(1000); //put thread to sleep for 1 second
}
} |