Java Forum / General / December 2005
How does Java make assignments atomic?
graftonfot@yahoo.com - 15 Dec 2005 16:17 GMT >From what I understand, Java guarantees that all assignments to primitive types (except non-volatile 64-bit types) will be atomic.
How does it do this? I thought that the only truly uninterruptable processor instruction was the test-and-set, and that test-and-set was the basis from which richer thread synchronization resources typically provided by an underlying operating system (e.g. semaphores, mutexes, critical sections) were built.
Does Java internally implement all of its generated assignment opcodes inside some kind of test-and-set-based wrappers?
Thanks.
Oliver Wong - 15 Dec 2005 23:15 GMT > >From what I understand, Java guarantees that all assignments to > primitive types (except non-volatile 64-bit types) will be atomic. [quoted text clipped - 7 lines] > Does Java internally implement all of its generated assignment opcodes > inside some kind of test-and-set-based wrappers? I think you are confusing several concepts here. First of all, for every single processor design I've encountered, none of the CPU instructions are "interruptable". Jump instructions, for example, are not interruptable, nor are ADD instructions, nor copying a value from one register to another.
In multiple processor designs, the individual processors don't "interrupt" each other either. What may pose problems is that they may have their own caches and have stale data if their caches do not accurately reflect what is in RAM.
It is not correct to say that Java "implements" anything. There is a Java Language Specification, and there is a Java Platform Specification. The specifications guarantee that all assignments on primitive types (with the exception noted above) are atomic. How that is accomplished is actually up to the implementor of the Java Platform.
Note though that there is no "Test And Set" bytecode instruction that I am aware of. Rather, the class files will contain normal "assignment" operators, which an interpreter or JIT compiler will have to translate into instructions which the CPU can understand.
If these instructions are storing primitive types whose size matches the wordsize of the architecture (e.g. ints on a 32 bit architecture), then I believe the "storage" instruction at the CPU level should already be atomic, so nothing special needs to be done. It's only when the wordsize is smaller than the java primitive size (e.g. java longs on 32 bit architecture, or java ints on 16 bit architecture), then typically the storing will need to be done in two or more instructions. Then something special needs to happen.
- Oliver
graftonfot@yahoo.com - 16 Dec 2005 04:23 GMT Let's limit the discussion to single processors for the time being. And, yes, OK, I wasn't 100% precise with my terminology, but from a practical perspective, I'd bet most people knew what I meant. So I could have said "any Java implementation that conforms to the JLS should guarantee that these assignments are atomic..." or something similar.
I'd agree (not that you asked me to) that single CPU instructions are probably not interruptable. But when the JLS states that, say, an integer assignment statement is guaranteed to be atomic, what does that cover? Which of the following are "assignment" statements for instance?
i = 4; i = j; i = j + k; i = 3 * x * y / z;
Which of these will be atomic? And will the simplest one (perhaps the first?) end up being implemented as a sequence of CPU instructions? If so, what does the Java implementation do to guarantee that that possibly-interruptable sequence of machine instructions will not in fact be interrupted? That was the intended crux of my question. Thanks.
Scott W Gifford - 16 Dec 2005 04:34 GMT [...]
> when the JLS states that, say, an > integer assignment statement is guaranteed to be atomic, what does that [quoted text clipped - 5 lines] > i = j + k; > i = 3 * x * y / z; They are all assignment statements.
> Which of these will be atomic? Speaking in general (I don't know Java's implementation details), all of the calculations on the right-hand side of the expression will be done at once, then stored atomically into the variable on the left-hand side. For example, in psuedoassembly, "i = j + k" might be:
MOV [j] -> ax ADD [k] -> ax MOV ax -> [i]
where just the final MOV has to be atomic in order for the assignment to be atomic.
Hope this helps,
-----Scott.
Roedy Green - 16 Dec 2005 09:41 GMT On Thu, 15 Dec 2005 23:34:07 -0500, Scott W Gifford <gifford@umich.edu> wrote, quoted or indirectly quoted someone who said :
> calculations on the right-hand side of the expression will be >done at once, then stored atomically into the variable on the [quoted text clipped - 6 lines] >where just the final MOV has to be atomic in order for the assignment >to be atomic. but the expression calculation is NOT done "at once", but in steps. Other threads could be meddling with the values of j and k at any point if you don't take special precautions. you might get the old or new value of j and k.
What is worse is the the actual code would likely look more like this
// ax contains j at this point // bx contains k at his point add ax,bx -> bx // bx contains j + k at this point mov bx -> i
So there is even more potential for a badly out of date j and k.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Scott W Gifford - 16 Dec 2005 19:53 GMT > On Thu, 15 Dec 2005 23:34:07 -0500, Scott W Gifford > <gifford@umich.edu> wrote, quoted or indirectly quoted someone who [quoted text clipped - 15 lines] > point if you don't take special precautions. you might get the old or > new value of j and k. Right, absolutely, but the incorrect result will be stored atomically: it will either have the old value, or the new (possibly incorrect) value, never something that's half one and half the other.
At least that's true in general; not sure about how Java does this specifically.
---ScottG.
Roedy Green - 16 Dec 2005 04:47 GMT >i = 4; >i = j; [quoted text clipped - 7 lines] >fact be interrupted? That was the intended crux of my question. >Thanks. As someone with an assembler background, it would never occur that was what you meant. If you want great hunks of code to run without interference like that you must protect the code and the variables in synchronized blocks.
The other thing to realise that variables typically have two homes, a register and a ram location. The register caches the ram value. Other threads will see the ram value and may have their own register caches. If you want other threads to see the latest value you must get the register value saved back before you let other threads peek. Volatile inhibits register caching, but just the same, all arithmetic has to go on in registers, so unless you have use synchronized, you will always see slightly out of date values.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Oliver Wong - 16 Dec 2005 20:12 GMT > I'd agree (not that you asked me to) that single CPU instructions are > probably not interruptable. But when the JLS states that, say, an [quoted text clipped - 13 lines] > fact be interrupted? That was the intended crux of my question. > Thanks. Only the action of assignment itself is atomic. So let me take the last example, first; the one that says "i = 3 * x * y / z;" The evaluation of the expression "3 * x * y / z" might not be atomic. But once that expression is evaluated (let's say it ends up being equal to 12), then placing the value of 12 into i is atomic. That is to say, it should be possible, in Java, for you to see "12" partially in i because only the first 8 bits of the register were set, and the 24 other bits are still random data.
Because CPU instructions are not interruptable, and the because storing the value 12 into a register can be done in a single instruction, the atomicity of the assignment happens "automagically" due to the way the x86 architecture is designed.
Now let's look at your second example, "i = j;" Again, ONLY the assignment is atomic. So it's possible that between the evaluation of the expression "j", and the storing of that value into "i", there is a thread switching that occurs. So the processor might read the value of j, but then a context switch occurs, and the value of j is updated, and then we switch back to the first thread, and the old value of j is stored into i.
- Oliver
Eric Sosman - 19 Dec 2005 20:06 GMT Oliver Wong wrote On 12/15/05 18:15,:
>>>From what I understand, Java guarantees that all assignments to >>primitive types (except non-volatile 64-bit types) will be atomic. [quoted text clipped - 12 lines] > "interruptable". Jump instructions, for example, are not interruptable, nor > are ADD instructions, nor copying a value from one register to another. It's sort of beside the main point, but quite a few processors provide interruptable instructions. Most that I've encountered are of the "self-repeating" variety: they'll do one operation, adjust a few registers, and keep on cycling until a register goes to zero or something. These are usually interruptible "between" the sub-operations; since the state is recorded in the registers, upon resumption they just pick up where they left off. String searches, memory moves -- heck, I've even used a processor that could do multiple I/O operations this way.
> In multiple processor designs, the individual processors don't > "interrupt" each other either. What may pose problems is that they may have > their own caches and have stale data if their caches do not accurately > reflect what is in RAM. Again somewhat beside the point, but I've never seen an MP machine (whether S or not) that didn't use CPU-to-CPU interrupts in some form. It might be possible to build one, but it's hard to imagine that the operation would be very efficient. Without an inter-CPU signalling mechanism, just booting the box in the first place seems pretty difficult.
> It is not correct to say that Java "implements" anything. There is a > Java Language Specification, and there is a Java Platform Specification. The > specifications guarantee that all assignments on primitive types (with the > exception noted above) are atomic. How that is accomplished is actually up > to the implementor of the Java Platform. ... and now we're back on track, and the rest seems reasonable. I might nit-pick about "architecture" versus "implementation" here and there, but Oliver's main point stands: the Java language and platform specify various guarantees and requirements, and it's up to the Java implementors to see that the requirements are met and the guarantees upheld.
 Signature Eric.Sosman@sun.com
Roedy Green - 16 Dec 2005 03:40 GMT >primitive types (except non-volatile 64-bit types) will be atomic. > >How does it do this? Bruce Eckel is puzzled too: http://www.artima.com/weblogs/viewpost.jsp?thread=126834
The atomicity of 32 bit operations is easy on a Pentium. The CPU does a store in a single cycle for 8, 16, 32 bits.
The atomicity of 64 bit ops is a problem, since the save needs two mov mem,reg instructions in a row without interruption and without another thread intervening at that locatation.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
graftonfot@yahoo.com - 19 Dec 2005 22:06 GMT My thanks for all who took the time to contribute and reply. If nothing else, the variety of replies suggests that there's a real possibility for confusion. I'm in a nearly pure Java shop right now, and I've heard "Java assignments are atomic" bandied about. I'd bet real money there are different understandings as to what that exactly means. Thanks again, all.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|