L. Cornelius Dol
L. Cornelius Dol

Reputation: 64026

Can I launch a thread from a constructor?

Given the J5+ memory model (JSR-133) is the following code thread-safe and permissible?

And if it's safe, is it acceptable in some situations?

public final class BackgroundProcessor
extends Object
implements Runnable
{

public BackgroundProcessor(...) {
    super();

    ...

    new Thread(this).start();
    }

public void run() {
    ...
    }
}

As I read the new JMM spec, initiating a thread creates a happens-before relationship with anything the initiated thread does.

Assume that the object has private member variables set in the constructor and used in run().

And the class is marked final to prevent sub-classing surprises.

Note: There is a similar question here, but this has a different angle: calling thread.start() within its own constructor

Upvotes: 3

Views: 572

Answers (3)

Neil Coffey
Neil Coffey

Reputation: 21795

Well, unless you particularly want to disagree with Brian Goetz on a Java concurrency issue, I'd assume it's wrong. Although his exact words are "is best not to...", I'd still heed his advice. From JCIP, p. 42:

"A common mistake that can let the 'this' reference escape during construction is to start a thread from a constructor [...] There's nothing wrong with creating a thread in a constructor, but it is best not to start the thread immediately. Instead, expose a start or initialize method..."

Update: just to elaborate on why this is a problem. Although there's guaranteed to be a memory barrier between the call to Thread.start() and that thread's run() method actually beginning to execute, there's no such barrier between what happens during the constructor after the call to Thread.start(). So if some other variables are still to be set, or if the JVM carries out some "have-just-constructed-object" housekeeping, neither of these are guaranteed to be seen by the other thread: i.e. the object could be seen by the other thread in an incomplete state.

Incidentally, aside from whether or not it actually breaks the JMM, it also just feels a bit like an "odd thing to do" in a constructor.

Upvotes: 3

Esko Luontola
Esko Luontola

Reputation: 73625

JLS: Threads and Locks says

Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.

If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.

  • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

and

A call to start() on a thread happens-before any actions in the started thread.

so we can conclude that all actions in the constructor before the call to Thread.start() happen before all actions in the thread that was started. If Thread.start() is after all writes to the object's fields, then the started thread will see all writes to the object's fields. If there are no other writes to the fields (that another thread will read), then the code is thread-safe.

Upvotes: 4

Roman
Roman

Reputation: 66156

  1. Your class should probably implements Runnable

  2. Yes, your code is OK

  3. It's not nessecary to extend Object. I'm sure that you know that Object is extended implicitly by all classes. I don't know where this popular practice to extend object explicitly comes from but it's a bad style.

Upvotes: -3

Related Questions