And in fact, in Java, the initial state is always all zeros or nulls whenever you start out with a blank class or you just allocate an object.
So if you have these two threads, and then you do the reads and the writes in opposite order, is it possible that thread 2 reads the b value of 2 and a value of 0?
And it’s a question for the audience if anybody wants to tackle it. Yes, OK. Right, so the answer is yes.
That’s a little bit counterintuitive since you would think that by reading them in opposite order, you’re essentially ensuring that if your latch b is 2, then a is 1.
So to explain that, let’s define a couple of terms first. So an action is a term I’m going to be using throughout the slides.
It means there’s a small unit of work that can be done atomically. And if you start out with source code, you have these large expressions.
They get broken down into actions following the evaluation order. So in real sort of files, it looks a lot like bytecode instructions on word size memory, and all of the examples later on are just single actions.
So another term is memory locations. That’s the largest unit of memory that can be modified or read through a single action.
And in all of our examples, the accesses are atomic. So what that means, if it’s non-atomic, then you can actually end up observing a partial write from another thread.
So for example, word tearing, where you see part– a 32-bit half of a 64-bit value.
So in the Java language specification, most of the primitives are guaranteed to be always atomic for memory access except for long and double.
Now, on the other hand, if you’re using code that’s compiled for ARM 64, it’s always going to be atomic no matter what for these primitives.
If you’re using an ARM 32, it’s likely atomic, like 99% of the time. On all the Pixels and all the Nexus devices, it’ll be always atomic.
However, like in reality, it’s an optional specification ARM V7 to make them atomic.
So if you get in trouble– if you want your code to work correctly on other devices out there, and of course, references and volatiles are always atomic.
So you don’t have to worry about that. And when I say atomic, for those of you with C++ background, think more like relaxed atomic.
All right, what about order? So if you have a bunch of source code, and there’s an evaluation order for that, order is called the program order.
So you can reorder those actions arbitrarily provided that same thread is not observed by reordering.
So we write this as PO with an arrow. And in this example, if you write to a twice and then read it in between each time, you could easily reorder that.
Or you end up writing– the start to the a ends up being the earlier one rather than the later one.
But as you can see, it’s unobservable by that thread, because no matter what it still reads the same values in either case.
And of course, in this example, we’re assuming that a might be overridden at some later point in time, or maybe it’s another access at some point in time.