Skip to main content

Are java primitive ints atomic by design or by accident?


Are java primitive integers (int) atomic at all, for that matter? Some experimentation with two threads sharing an int seems to indicate that they are , but of course absence of evidence that they are not does not imply that they are.



Specifically, the test I ran was this:




public class IntSafeChecker {
static int thing;
static boolean keepWatching = true;

// Watcher just looks for monotonically increasing values
static class Watcher extends Thread {
public void run() {
boolean hasBefore = false;
int thingBefore = 0;

while( keepWatching ) {
// observe the shared int
int thingNow = thing;
// fake the 1st value to keep test happy
if( hasBefore == false ) {
thingBefore = thingNow;
hasBefore = true;
}
// check for decreases (due to partially written values)
if( thingNow < thingBefore ) {
System.err.println("MAJOR TROUBLE!");
}
thingBefore = thingNow;
}
}
}

// Modifier just counts the shared int up to 1 billion
static class Modifier extends Thread {
public void run() {
int what = 0;
for(int i = 0; i < 1000000000; ++i) {
what += 1;
thing = what;
}
// kill the watcher when done
keepWatching = false;
}
}

public static void main(String[] args) {
Modifier m = new Modifier();
Watcher w = new Watcher();
m.start();
w.start();
}
}



(and that was only tried with java jre 1.6.0_07 on a 32bit windows PC)



Essentially, the Modifier writes a count sequence to the shared integer, while the Watcher checks that the observed values never decrease. On a machine where a 32 bit value had to be accessed as four separate bytes (or even two 16bit words), there would be a probability that Watcher would catch the shared integer in an inconsistent, half-updated state, and detect the value decreasing rather than increasing. This should work whether the (hypothetical) data bytes are collected/written LSB 1st or MSB 1st, but is only probablistic at best.



It would seem very probable given today's wide data paths that a 32 bit value could be effectively atomic, even if the java spec doesn't require it. In fact, with a 32 bit data bus it would seem that you might have to work harder to get atomic access to bytes than to 32 bit ints.



Googling on "java primitive thread safety" turns up loads of stuff on thread-safe classes and objects, but looking for the info on the primitives seems to be looking for the proverbial needle in a haystack.


Source: Tips4allCCNA FINAL EXAM

Comments

  1. All memory accesses in Java are atomic by default, with the exception of long and double (which may be atomic, but don't have to be). It's not put very clearly to be honest, but I believe that's the implication.

    From section 17.4.3 of the JLS:


    Within a sequentially consistent
    execution, there is a total order over
    all individual actions (such as reads
    and writes) which is consistent with
    the order of the program, and each
    individual action is atomic and is
    immediately visible to every thread.


    and then in 17.7:


    Some implementations may find it
    convenient to divide a single write
    action on a 64-bit long or double
    value into two write actions on
    adjacent 32 bit values. For
    efficiency's sake, this behavior is
    implementation specific; Java virtual
    machines are free to perform writes to
    long and double values atomically or
    in two parts.


    Note that atomicity is very different to volatility though.

    When one thread updates an integer to 5, it's guaranteed that another thread won't see 1 or 4 or any other in-between state, but without any explicit volatility or locking, the other thread could see 0 forever.

    With regard to working hard to get atomic access to bytes, you're right: the VM may well have to try hard... but it does have to. From section 17.6 of the spec:


    Some processors do not provide the
    ability to write to a single byte. It
    would be illegal to implement byte
    array updates on such a processor by
    simply reading an entire word,
    updating the appropriate byte, and
    then writing the entire word back to
    memory. This problem is sometimes
    known as word tearing, and on
    processors that cannot easily update a
    single byte in isolation some other
    approach will be required.


    In other words, it's up to the JVM to get it right.

    ReplyDelete
  2. No amount of testing can prove thread safety - it can only disprove it;
    I found a indirect reference in JLS 17.7 which states



    Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32 bit values.


    and further down


    For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half.


    This seems to imply that writes to ints are atomic.

    ReplyDelete
  3. A read or write from integer or any smaller type should be atomic, but as Robert noted, longs and doubles may or may not depending on the implementation. However, any operation that uses both a read and a write, including all of the increment operators, are not atomic. Thus, if you have to threads operating on an integer i=0, one does i++ and the other does i=10, the result could be 1, 10, or 11.

    For operations like this, you should look at AtomicInteger which has methods for atomically modifying a value while retrieving the old one or to atomically increment the value.

    Finally, threads may cache the value of the variable and won't see changes made to it from other threads. To make sure that both threads always see changes made by the other thread, you need to mark the variable as being volatile.

    ReplyDelete
  4. This is somewhat complicated, and is related to system wordsize. Bruce Eckel discusses it in more detail: Java Threads.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex