acejazz
acejazz

Reputation: 819

Why in certain circumstances, updates from a thread are not visible although the update is made?

I'm reading "Effective Java" and in the chapter where he's talking about threads, I stepped into this snippet:

private static int nextSerialNumber = 0;

public static int generateSerialNumber(){
    return nextSerialNumber++;
}

A bit later, talking that snippet but in case there is no synchronization, he says:

More surprisingly, it is possible for one thread to call generateSerialNumber repeatedly, obtaining a sequence of serial numbers from zero to n, after which another thread calls generateSerialNumber and obtains a serial number of zero. Without synchronization, the second thread might see none of the updates made by the first. This is a result of the aforementioned memory model issue.

I can't understand how this is possible. For the thread to obtain "a sequence of serial numbers from zero to n", the increment must be done, otherwise the thread will read always the same value. If the increment is done, then the variable is set, because being an int, the writing is atomic. So, if the static variable is changed by a thread, although it might be the same one, another thread must be able to read that value. So how is possible that another thread, calling generateSerialNumber, can obtain a serial number of zero?

Upvotes: 2

Views: 226

Answers (2)

Kayaman
Kayaman

Reputation: 73538

because being an int, the writing is atomic.

That just means it's not possible for another thread to see a half-updated value, it's either the old one or the new one (in 64-bit systems this extends to long variables).

It has nothing to do with the basic visibility problem meaning that unless your variable is volatile or you're using synchronization the value can and will be cached by different threads for performance purposes and you will see old cached values instead of up to date ones.

In addition, nextSerialNumber++; is not atomic as it consists of read-update-write steps, so making nextSerialNumber volatile won't fix this code. The method needs to be synchronized.

Upvotes: 4

Mark Rotteveel
Mark Rotteveel

Reputation: 108971

The current value of nextSerialNumber might be cached in a cache local to the core, and updates to that value might also be cached for a while until they are flushed to main memory. So when using multiple threads, scheduled on different cores, they might have their own local cached version of nextSerialNumber.

When not explicitly instructed, the code (and CPU) will assume it is fine to use this local cached version, and happily read and update the cached variable, while another thread scheduled on a different core will happily do the same with its own cached version.

When using concurrency primitives like synchronized and volatile, this changes. For a synchronized-block (simplified) the Java implementation will make sure those values will be retrieved from main memory when first read and written back to main memory at the end of a synchronized block, it does the same for volatile variables, but then at each read and write.

In reality things are a bit more complicated, with happens-before relations between threads, etc. But basically, your question boils down to "blame caching".

Upvotes: 2

Related Questions