Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当我试图在java中杀死一个线程时,会发生奇怪的事情吗?_Java_Multithreading - Fatal编程技术网

当我试图在java中杀死一个线程时,会发生奇怪的事情吗?

当我试图在java中杀死一个线程时,会发生奇怪的事情吗?,java,multithreading,Java,Multithreading,我有一个“串行”类,它扩展了使用串行端口的线程。在run()方法中,我首先打开端口,设置所有串行参数并添加一个SerialPortEventListener。然后我把while(go)放在其中,go是一个私有的(只有类才能看到它)布尔实例,设置为true。我有一个kill方法,它不仅关闭端口并删除SerialEventListener,而且还将“go”设置为false,因此线程应该停止。现在,事情开始变得奇怪了:如果我在while(go)中放置一个System.out.println(somet

我有一个“串行”类,它扩展了使用串行端口的线程。在run()方法中,我首先打开端口,设置所有串行参数并添加一个SerialPortEventListener。然后我把while(go)放在其中,go是一个私有的(只有类才能看到它)布尔实例,设置为true。我有一个kill方法,它不仅关闭端口并删除SerialEventListener,而且还将“go”设置为false,因此线程应该停止。现在,事情开始变得奇怪了:如果我在while(go)中放置一个System.out.println(something),当我调用kill()方法时,Thred停止,但如果我不这样做,它将保持活动状态。你对它为什么会这样工作以及如何解决它有什么想法吗

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等人的经典著作。