Why not to start a thread in the constructor? How

2019-01-01 15:54发布

问题:

I am learning how to use threads in Java. And I wrote a class that implements Runnable to run concurrently to another thread. The main thread handles listening to the serial port where as the second thread will handle sending data to that same port.

public class MyNewThread implements Runnable {
    Thread t;

    MyNewThread() {
        t = new Thread (this, \"Data Thread\");
        t.start();
    }

    public void run()  {
        // New Thread code here 
    }

There first thread starts the second like this:

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

This works but my complier flags a warning saying: It is dangerous to start a new thread in the constructor. Why is this?

The second part to this question is: how if I have a loop running in one thread (the serial port listen thread) and I type an exit command in my second thread. How do I get the first thread to terminate? Thanks.

回答1:

To your first question: Starting a thread in a constructor passing in this escapes this. That means that you are actually giving out a reference to your object before it is fully constructed. The thread will start before your constructor finishes. This can result in all kinds of weird behaviors.

To your second question: There is no acceptable way to force another thread to stop in Java, so you would use a variable which the thread would check to know whether or not it should stop. The other thread would set it to indicate that the first thread would stop. The variable has to be volatile or all accesses synchronized to ensure proper publication. Here is some code which would be something like what you want.

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

Whatever wants to create and start the thread would do:

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

Whatever wants to stop the thread would do:

thread.stop();


回答2:

Lets take a look at a basic example:

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

In this instance the MyClass.this is said to escape the constructor. That means that the object is available to reference but all of its fields that are being built in the constructor may not be created. To take this to another level what if b was final You would expect it to be available but it is not ensured. This is known as a partially constructed objects and is perfectly legal in java.



回答3:

about second question , you can check if second thread has been terminated or not by isAlive method and if yes use break keyword to turn off the looping for first thread then will be terminated if nothing has to do

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

}  
}


回答4:

The second part to this question is: how if I have a loop running in one thread (the serial port listen thread) and I type an exit command in my second thread. How do I get the first thread to terminate?

Have it keep looping until a condition has been reached. For example:

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