当我试图在java中终止线程时会发生奇怪的事情?

iih3973s  于 2021-07-12  发布在  Java
关注(0)|答案(2)|浏览(222)

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

while(go) {
            System.out.println("in");
        }
public void kill(){
        go = false;
        try {
            this.serialPort.removeEventListener();
            this.serialPort.closePort();
        } catch (SerialPortException e) {
            e.printStackTrace();
        }
    }
jhdbpxl9

jhdbpxl91#

我不想争论你实现这些线程的方式。然而,看看具体的场景,你有一个 Serial 类,只要变量 gotrue . 同样的变量也可以由另一个线程(即主线程)在方法完成后进行更改 kill 已调用。
正如@wjs所建议的,使事情正常工作的最佳方法是声明变量 go “易失性”。你应该有这样的东西:

public class Serial extends Thread {
   ...
   private volatile boolean go;
   ...

   public void kill(){
      ...
   }
   ...
}

基本上,通过这种方式,jvm确保不同的线程读取一个一致的变量值,而实际上这正是像您这样的多线程场景中发生的事情。
另一种方法是将变量go定义为 java.util.concurrent.atomic.AtomicBoolean ,而不是把它当作简单的原语 boolean . 在这种情况下,这种方法也非常有效,因为通过这种方式,jvm保证变量值的每一次更改都是原子操作,这意味着使其成为“一”,并且您将始终避免任何可能的争用条件。
在这种情况下,您的代码应该是这样的:

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);
       ...
    }
}
8wigbo56

8wigbo562#

除非 go 如果声明为volatile,则不能保证while循环(或其他任何东西)将读取当前值。
宣布进入

volatile boolean go;

然后它应该可以工作(除非还有其他事情没有发布)。而这样做并不能减轻进行适当同步的需求。

相关问题