为什么不在构造函数中启动一个线程?如何终止?

Zac*_*Zac 46 java multithreading terminate

我正在学习如何在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 
    }
Run Code Online (Sandbox Code Playgroud)

第一个线程开始第二个像这样:

public class Main {
    public static void main(String[] args) throws Exception{
        new MyNewThread();
        // First thread code there
    }  
}
Run Code Online (Sandbox Code Playgroud)

这有效,但我的编译器标记了一个警告说:在构造函数中启动一个新线程是危险的.为什么是这样?

这个问题的第二部分是:如果我在一个线程中运行一个循环(串口侦听线程),我在第二个线程中键入一个exit命令.如何获得第一个终止线程?谢谢.

Jus*_*ugh 45

第一个问题:在传递this转义的构造函数中启动一个线程this.这意味着您实际上是在完全构造对象之前给出了对象的引用.线程将在构造函数完成之前启动.这可能导致各种奇怪的行为.

对于你的第二个问题:没有可接受的方法强制另一个线程在Java中停止,所以你将使用一个线程将检查的变量来知道它是否应该停止.另一个线程将其设置为指示第一个线程将停止.变量必须是volatile或所有访问同步以确保正确发布.这里有一些代码可能就像你想要的那样.

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
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

无论想要创建和启动线程,都可以:

MyNewThread thread = new MyNewThread();
thread.start();
Run Code Online (Sandbox Code Playgroud)

无论什么想要阻止线程会做:

thread.stop();
Run Code Online (Sandbox Code Playgroud)

  • @Justin,"要使用没有同步的volatile,你需要确保只有一个线程会修改它,这不是这里的情况." ......这是错的.对volatile变量的更改对其他线程可见而无需进一步同步.编写一个volatile变量并随后读取同一个变量会创建"之前发生"关系,这种关系保证在Java Memory Model中可见.有关详细信息(或JMM规范),请参阅http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility. (3认同)

Joh*_*int 9

让我们来看一个基本的例子:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,MyClass.this被称为逃避构造函数.这意味着该对象可用于引用,但可能无法创建在构造函数中构建的所有字段.把这个带到另一个层次,如果b是final 你会期望它可用但是不能确保.这被称为部分构造的对象,在java中完全合法.