views:

70

answers:

3

Does the out variable in the MyThread class need to be declared volatile in this code or will the "volatility" of the stdout variable in the ThreadTest class carry over?

import java.io.PrintStream;

class MyThread implements Runnable
{
    int id;
    PrintStream out; // should this be declared volatile?

    MyThread(int id, PrintStream out) {
        this.id = id;
        this.out = out;
    }

    public void run() {
        try {
            Thread.currentThread().sleep((int)(1000 * Math.random()));
            out.println("Thread " + id);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadTest
{
    static volatile PrintStream stdout = System.out;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new MyThread(i, stdout)).start();
        }
    }
}
A: 

It definitely won't carry over. I'm not sure what you're trying to do, though. volatile qualifies the field in ThreadTest, not the value.

Matthew Flaschen
A: 

Does the out variable in the MyThread class need to be declared volatile in this code or will the "volatility" of the stdout variable in the ThreadTest class carry over?

The volatility does not "carry over" because you actually passing the value of the variable.

According to my reading of the JLS memory model spec, a volatile is required if you were to read out without some intervening synchronization between the thread that created the object and the thread that uses it. But a better solution would be to declare out as final. The semantics of final fields mean that no synchronization is required.

Stephen C
+1  A: 

The volatile qualifier won't carry through, and it serves no purpose in the above code. Volatile establishes a memory barrier on reads and writes to the variable, which is never modified once initialised in the constructor. For the same reason, the volatile qualifier in ThreadTest serves no purpose either.

Just to be clear, volatile applies to the variable, not to the referenced object.

Marcelo Cantos
Ummm ... my reading of the JLS memory model spec is that there is no "happens-before" relationship between writing a (non-volatile, non-final) field in a constructor and reading it in another thread. So that makes the `volatile` qualifier non-redundant in the example.
Stephen C
@Stephen C, it is impossible for another thread to access the variable before the constructor returns.
Marcelo Cantos
Not unless the object is "unsafely published" by the constructor (not the case here). But here we are talking about another thread accessing the variable after the constructor returns; i.e. in the `run` method.
Stephen C
I'm sorry, Stephen, but I just don't see it. You construct the object, setting the variable once, for all time, and then pass it to another thread, which accesses that same variable that has not changed and will never change. Where in this picture is `volatile` warranted?
Marcelo Cantos
@Marcelo - the problem is that nothing in the JLS says that the constructor WILL flush the variable contents to main memory. Therefore, if the other thread is executing on a different processor, it may get a stale copy of `out` when it reads it. That is what the Java memory model is all about. I strongly recommend that you read the sections of the JLS that my answer links to.
Stephen C
Ok, I had a look. The happens-before relationships in 17.4.5 should apply as follows: hb(write to the field, pass the new object to another thread) (first rule); hb(pass the object to another thread, the other thread receives the object) (third rule); hb(the other receives the object, the other thread reads the field) (first rule), therefore hb(write to the field, the other thread reads the field) (fourth rule). In short, passing the new object to another thread via any kind of synchronisation mechanism (queue, lock, etc.) ought to guarantee that the write happens before the read.
Marcelo Cantos