Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 4535

Why Not To Start A Thread In The Constructor?

$
0
0

1. Overview

In this quick tutorial, we're going to see why we shouldn't start a thread inside a constructor.

First, we'll briefly introduce the publication concept in Java and JVM. Then, we'll see how this concept affects the way we start threads.

2. Publication and Escape

Every time we make an object available to any other code outside of its current scope, we basically publish that object. For instance, publishing happens when we return an object, store it into a public reference, or even pass it to another method.

When we publish an object that we shouldn't have, we say that the object has escaped.

There are many ways that we can let an object reference escape, such as publishing the object before its full construction. As a matter of fact, this is one of the common forms of escape: when the this reference escapes during object construction.

When the this reference escapes during construction, other threads may see that object in an improper and not fully-constructed state. This, in turn, can cause weird thread-safety complications.

3. Escaping with Threads

One of the most common ways of letting the this reference escape is to start a thread in a constructor. To better understand this, let's consider an example:

public class LoggerRunnable implements Runnable {

    public LoggerRunnable() {
        Thread thread = new Thread(this); // this escapes
        thread.start();
    }

    @Override
    public void run() {
        System.out.println("Started...");
    }
}

Here, we explicitly pass the this reference to the Thread constructor. Therefore, the newly started thread might be able to see the enclosing object before its full construction is complete. In concurrent contexts, this may cause subtle bugs.

It's also possible to pass the this reference implicitly:

public class ImplicitEscape {
    
    public ImplicitEscape() {
        Thread t = new Thread() {

            @Override
            public void run() {
                System.out.println("Started...");
            }
        };
        
        t.start();
    }
}

As shown above, we're creating an anonymous inner class derived from the Thread. Since inner classes maintain a reference to their enclosing class, the this reference again escapes from the constructor.

There's nothing inherently wrong with creating a Thread inside a constructor. However, it's highly discouraged to start it immediately, as most of the time, we end up with an escaped this reference, either explicitly or implicitly.

3.1. Alternatives

Instead of starting a thread inside a constructor, we can declare a dedicated method for this scenario:

public class SafePublication implements Runnable {
    
    private final Thread thread;
    
    public SafePublication() {
        thread = new Thread(this);
    }

    @Override
    public void run() {
        System.out.println("Started...");
    }
    
    public void start() {
        thread.start();
    }
};:

As shown above, we still publish the this reference to the Thread. However, this time, we start the thread after the constructor returns:

SafePublication publication = new SafePublication();
publication.start();

Therefore, the object reference does not escape to another thread before its full construction.

4. Conclusion

In this quick tutorial, after a brief introduction to the safe publication, we saw why we shouldn't start a thread inside a constructor.

More detailed information about the publication and escape in Java can be found in the Java Concurrency in Practice book.

As usual, all the examples are available over on GitHub.


Viewing all articles
Browse latest Browse all 4535

Trending Articles