views:

193

answers:

6

I'm trying to figure out if the code below suffers from any potential concurrency issues. Specifically, the issue of visibility related to volatile variables. Volatile is defined as: The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory"

public static void main(String [] args)
{
    Test test = new Test();

    // This will always single threaded
    ExecutorService ex = Executors.newSingleThreadExecutor();

    for (int i=0; i<10; ++i)
        ex.execute(test);
}

private static class Test implements Runnable {
    // non volatile variable in question
    private int state = 0;

    @Override
    public void run() {
        // will we always see updated state value? Will updating state value
        // guarantee future run's see the value?
        if (this.state != -1)
            this.state++;
    }
}

For the above single threaded executor:

Is it okay to make test.state non volatile? In other words, will every successive Test.run() (which will occur sequentially and not concurrently because again executor is single threaded), always see the updated test.state value? If not, doesn't exiting of Test.run() ensure any changes made thread locally get written back to main memory? Otherwise when does changes made thread locally get written back to main memory if not upon exiting of the thread?

A: 

If your ExecutorService is single threaded then there is no shared state, so I don't see how there could be any issues around that.

However wouldn't it make more sense to pass a new instance of your Test class to each call to execute()? i.e.

for (int i=0; i<10; ++i)
    ex.execute(new Test());

This way there will not be any shared state.

matt b
That doesn't make any sense whatsoever, the whole point of the question is that the same object is used.
KernelJ
+3  A: 

As long as it's only a single thread there is no need to make it volatile. If you're going to use multiple threads, you should not only use volatile but synchronize too. Incrementing a number is not an atomic operation - that's a common misconception.

public void run() {
    synchronize (this) {
        if (this.state != -1)
            this.state++;
    }
}

Instead of using synchronization, you could also use AtomicInteger#getAndIncrement() (if you won't need an if before).

private AtomicInteger state = new AtomicInteger();

public void run() {
    state.getAndIncrement()
}
sfussenegger
I was just asking a simple question of whether state changes will be seen by other threads in a single threaded mode and you answered that. However getting off topic, I don't see why I need to use volatile AND synchronize. It seems to me synchronizing would suffice.
Integer
I just wanted to make you (and others stumbling upon this question) aware of the fact that using volatile for incrementing an integer does not suffice in a multi-threaded environment. You'll always need both, volatile and synchronized to be thread-safe.
sfussenegger
The reason why volatile often does not suffice is clear to me: since the non-atomicity of ++ some of the increments of the threads might not have an effect due to race conditions. But why should synchronization without volatile not be sufficient? If you synchronize reads as well, of course.
hstoerr
@hstoerr synchronization without volatile is sufficient, using volatile (where suffiscient) has less overhead though (see http://j.mp/7RrAzi). Still, I'd always use a combination of both, regardless of performance: better save than sorry. Concurrent access to unsynchronized fields might get especially problematic if you are dealing with 64 bit types (long, double) where even reads and writes aren't guaranteed to be atomic: they might be split into two 32 bit operations. So one might even read a mix of two completely different values.
sfussenegger
A: 

Your code, specifically this bit

            if (this.state != -1)
                    this.state++;

would require the atomic test of the state value and then an increment to the state in a concurrent context. So even if your variable was volatile and more than one thread was involved, you would have concurrency issues.

But your design is based on asserting that there will always only be one instance of Test, and, that single instance is only granted to a single (same) thread. (But note that the single instance is in fact a shared state between the main thread and the executor thread.)

I think you need to make these assumptions more explicit (in the code, for example, use the ThreadLocal and ThreadLocal.get()). This is to guard both against future bugs (when some other developer may carelessly violate the design assumptions), and, guard against making assumptions about the internal implementation of the Executor method you are using which may in some implementations simply provide single threaded executor (i.e. sequential and not necessarily the same thread in each invocation of execute(runnable).

Listen, i know the code isn't a work of art. I understand there are millions of improvements that can be made. Yes, i know about threadlocals, i know about synchronizing and atomic variables. It's not production code. It's made code to illustrate my question of concurrent visibility and volatile.
Integer
A: 

It is perfectly fine for state to be non-volatile in this specific code, because there is only one thread, and only that thread accesses the field. Disabling caching the value of this field within the only thread you have will just give a performance hit.

However if you wish to use the value of state in the main thread which is running the loop, you have to make the field volatile:

    for (int i=0; i<10; ++i) {
            ex.execute(test);
            System.out.println(test.getState());
    }

However, even this might not work correctly with volatile, because there is no synchronization between the threads.

Since the field is private, there is only an issue if the main thread executes a method that can access this field.

KernelJ
+3  A: 

Originally, I was thinking this way:

If the task were always executed by the same thread, there would be no problem. But Excecutor produced by newSingleThreadExecutor() may create new threads to replace a those that are killed for any reason. There is no guarantee about when the replacement thread will be created or which thread will create it.

If a thread performs some writes, then calls start() on a new thread, those writes will be visible to the new thread. But there is no guarantee that that rule applies in this case.

But irreputable is right: creating a correct ExecutorService without sufficient barriers to ensure visibility is practically impossible. I was forgetting that detecting the death of another thread is a synchronizes-with relationship. The blocking mechanism used to idle worker threads would also require a barrier.

erickson
"There is no guarantee about when the replacement thread will be created or which thread will create it." Whether executor runs Test in the same thread or replacement thread, does it make a difference? Because I'm using the same instance of Test(). My question is specific to whether all executions of Test.run() will see the previously updated State value.
Integer
Yes, whether or not the same thread is used to run `Test` makes all the difference. If a single thread is guaranteed to run all executions of `run()`, then it's just normal, single-threaded programming, and the updates will certainly be seen in subsequent invocations by that thread. However, because the task uses no memory barriers, those updates might not be visible to a *different* thread, including a replacement thread created by the executor.
erickson
Thank you. You answered my question perfectly.
Integer
I'm sorry this answer is incorrect, see my reply below. You cannot provide an implementation of `newSingleThreadExecutor()` that satisfies its javadoc, yet fails to synchronize different run()'s.
irreputable
+1  A: 

Yes it is safe, even if the executor replaced its thread in the middle. Thread start/terminate are also synchronization points.

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

A simple example:

static int state;
static public void main(String... args) {
    state = 0;                   // (1)
    Thread t = new Thread() {
        public void run() {
            state = state + 1;   // (2) 
        }
    };
    t.start();
    t.join();
    System.out.println(state);  // (3)
}

It is guaranteed that (1), (2), (3) are well ordered and behave as expected.

For the single thread executor, "Tasks are guaranteed to execute sequentially", it must somehow detect the finish of one task before starting the next one, which necessarily properly synchronizes the different run()'s

irreputable