当我试图在java中杀死一个线程时,会发生奇怪的事情吗?
我有一个“串行”类,它扩展了使用串行端口的线程。在run()方法中,我首先打开端口,设置所有串行参数并添加一个SerialPortEventListener。然后我把while(go)放在其中,go是一个私有的(只有类才能看到它)布尔实例,设置为true。我有一个kill方法,它不仅关闭端口并删除SerialEventListener,而且还将“go”设置为false,因此线程应该停止。现在,事情开始变得奇怪了:如果我在while(go)中放置一个System.out.println(something),当我调用kill()方法时,Thred停止,但如果我不这样做,它将保持活动状态。你对它为什么会这样工作以及如何解决它有什么想法吗当我试图在java中杀死一个线程时,会发生奇怪的事情吗?,java,multithreading,Java,Multithreading,我有一个“串行”类,它扩展了使用串行端口的线程。在run()方法中,我首先打开端口,设置所有串行参数并添加一个SerialPortEventListener。然后我把while(go)放在其中,go是一个私有的(只有类才能看到它)布尔实例,设置为true。我有一个kill方法,它不仅关闭端口并删除SerialEventListener,而且还将“go”设置为false,因此线程应该停止。现在,事情开始变得奇怪了:如果我在while(go)中放置一个System.out.println(somet
while(go) {
System.out.println("in");
}
除非
go
声明为volatile,否则不能保证while循环(或其他任何内容)将读取当前值
宣布成为
volatile boolean go;
然后它应该会工作(除非还有其他事情没有发布)。这样做并不能减轻进行适当同步的要求。我不想讨论您实现这些线程的方式。但是,看看具体的场景,您有一个
Serial
类,只要变量go
为true
,它就会保持活动状态并执行其工作。调用方法kill
后,另一个线程(即主线程)也可以更改相同的变量。正如@WJS所建议的,使事情正常工作的最佳方法是将变量
go
声明为“volatile”。你应该有这样的东西:
public class Serial extends Thread {
...
private volatile boolean go;
...
public void kill(){
...
}
...
}
import java.util.concurrent.atomic.AtomicBoolean;
...
public class Serial extends Thread {
private AtomicBoolean go = new AtomicBoolean(true);
...
public void loop() {
...
while(go.get()) {
}
}
public kill() {
atomicBoolean.set(false);
...
}
}
基本上,通过这种方式,JVM确保不同的线程读取变量的一致值,并且实际上这就是像您这样的多线程场景中发生的情况
另一种方法是将变量go定义为java.util.concurrent.AtomicBoolean
,而不是将其定义为简单的基元boolean
。在这种情况下,这也非常有效,因为通过这种方式,JVM保证变量值的每一次更改都是一个原子操作,这意味着将其设置为“一”,并且您将始终避免任何可能的争用条件。在这种情况下,您的代码应该是这样的:
public class Serial extends Thread {
...
private volatile boolean go;
...
public void kill(){
...
}
...
}
import java.util.concurrent.atomic.AtomicBoolean;
...
public class Serial extends Thread {
private AtomicBoolean go = new AtomicBoolean(true);
...
public void loop() {
...
while(go.get()) {
}
}
public kill() {
atomicBoolean.set(false);
...
}
}
在没有保护的情况下,决不能从两个线程访问同一变量。正如你已经发现的,这是一个灾难的秘诀。你需要某种形式的治疗,我该怎么做?我可以将同步字添加到kill()方法中吗?您需要同步对变量的所有访问,而不仅仅是
kill
中的修改。当您在run
中访问它时,它也需要同步(使用块,而不是整个方法;如果您同步整个run
方法,您将永远无法调用kill
),谢谢您的时间,请您提供一个示例代码好吗?正如您所知,我只在while(go)(在run()方法中)中访问变量“go”,而在Java语言规范的kill()中对其进行了很好的解释。坏消息:我不知道“volatile”是什么意思,也不知道如何进行同步,请您帮助我好吗?不幸的是,这是一个复杂的主题,需要花费太多的时间。但是您可以在上查看这一部分,该部分讨论如何正确地同步线程。关键字volatile
在原子访问
一节中介绍。网络上还有其他来源。当出现具体问题时,你可以回到SO并就此提出问题。您也可以搜索同步
主题,因为它以前已经讨论过很多次了。@DavidePasero坦率地说,如果您不理解volatile
(以及原子…
类),您就不应该进行线程/并发编程。阅读本网站上的Oracle教程、搜索和研究文章,最重要的是,阅读Brian Goetz等人的经典著作。