【问题标题】:Why not to start a thread in the constructor? How to terminate?为什么不在构造函数中启动一个线程?如何终止?
【发布时间】:2011-08-03 03:46:01
【问题描述】:

我正在学习如何在 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 
    }

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

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

这可行,但我的编译器标记了一条警告:在构造函数中启动新线程很危险。这是为什么呢?

这个问题的第二部分是:如果我在一个线程(串行端口侦听线程)中运行一个循环并且我在我的第二个线程中键入退出命令。如何让第一个线程终止?谢谢。

【问题讨论】:

  • 最好将问题的第二部分分叉到另一个线程中,呃,我的意思是,问题。
  • 考虑为问题的第二部分询问实际的第二个 StackOverflow 问题。这将为您提供每个问题的最佳答案。
  • 第一个问题在这里得到了回答:stackoverflow.com/questions/84285/…。由于第二部分,我不会投票关闭作为重复...现在这变得复杂,因为已经有答案:(

标签: java multithreading terminate


【解决方案1】:

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

关于您的第二个问题:在 Java 中没有可接受的强制另一个线程停止的方法,因此您将使用一个变量,该线程将检查它是否应该停止。另一个线程将设置它以指示第一个线程将停止。该变量必须是易失的或所有访问同步以确保正确发布。这里有一些你想要的代码。

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
         }
    }
}

只要想创建和启动线程就行:

MyNewThread thread = new MyNewThread();
thread.start();

任何想停止线程都会做的事情:

thread.stop();

【讨论】:

  • 在构造函数中启动线程只有在您实际发布 this 时才会发布 this(如上面的代码中所示,即便如此,发布的还是构造函数调用)。 foo = new SomeSpecialThread(); foo.start(); 没有发布这个,或者是吗?现在,在 它自己的 构造函数上启动一个线程确实会暴露一个不完整的对象。
  • @seh:不需要,因为对它的所有访问都是同步的。 @Justin:从Thread继承不是更好吗?
  • @Justin,“要使用不同步的 volatile,您需要确保只有一个线程会修改它,而这里不是这种情况。” ……这是错误的。对 volatile 变量的更改对其他线程可见,无需进一步同步。写入一个 volatile 变量并随后读取相同的变量会创建“先发生”关系,这保证在 Java 内存模型中是可见的。有关详细信息(或 JMM 规范),请参阅 download.oracle.com/javase/6/docs/api/java/util/concurrent/…
  • @Peter 您当然是对的,我误读了 JCIP 中的声明。只有当写入变量确实取决于其当前值时,您必须确保只有一个线程正在更新值
  • @shareef:你在这里看到的.stop()不是来自java.lang.Thread的那个,而是一个独立的。虽然名称对 startstop 非常好,但您说得对,它不应该在 Java 线程的上下文中使用,因为它看起来像被禁止的 Thread.stop() 方法。
【解决方案2】:

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

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 被称为 escape 构造函数。这意味着该对象可用于引用,但可能不会创建在构造函数中构建的所有字段。如果 b 是final 将其提升到另一个层次,您会期望它可用,但不能保证。这被称为部分构造的对象,在 java 中是完全合法的。

【讨论】:

    【解决方案3】:

    关于第二个问题, 您可以通过isAlive 方法检查第二个线程是否已终止,如果是,则使用break 关键字关闭第一个线程的循环,然后如果无事可做将被终止

    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 
    }
    

    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() 方法等待而类线程运行。它应该在带有睡眠暂停的 while 循环中调用,包含在 try/catch 块中,寻找 InterruptedException。
    【解决方案4】:

    这个问题的第二部分是: 如果我有一个循环运行在一个 thread(串口监听线程) 我在我的 第二个线程。我如何获得第一 线程要终止?

    让它一直循环直到达到一个条件。例如:

    public void run() {
        while ( !inputConsole.getCommand().equals("exit") ) {
            //Do Something
            Thread.sleep(1000); //put thread to sleep for 1 second
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多