Auch ein volatiles int hat zum Beispiel keine atomare Schreiboperation, es kann also passieren dass bei der Zuweisung a=b; ein Thread einen ungültigen Wert liest der weder a noch b ist. Auch wenn das in der Praxis sehr rar vorkommt. Mit AtomicInteger wird das vermieden.
Und auch das ist nicht korrekt.
Das Java Memory Model garantiert, dass Schreib- und Lesezugriffe auf volatile Variablen
immer atomar sind, also kein Thread nur einen "Teilbereich" des Datentypen lesen kann während ein anderer Thread gerade schreibt.
Und sogar non-volatile ints sind atomar. Also, selbst, wenn man ein int nicht als volatile markiert, können solche "Zwischenzustände" nicht gelesen werden.
Nur für long und double gibt es eine explizite Unterscheidung bezüglich Atomarität:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7
Damit wurde der Fall mit aufgenommen, wenn man die JVM als 32-bit Prozess laufen lässt und 64-bit Werte (eben long oder double) schreibt - da ein 32-bit Prozess keine 64-bit Speicher/-Memorytransaktionen verwendet. Hier garantiert das JLS nur Atomarität auf 32-bit Teilbereichen.
Aber für als volatile markierte Variablen ist der Zugriff immer atomar (auch für longs und doubles)!
kleiner Hinweis, um das obige nicht falsch zu verstehen: Atomar bedeutet hier nicht, dass jede Operation wie etwa i++ auf einer Variablen i atomar ist, sondern direkte Lese- und Schreibzugriffe sind atomar! i++ sind drei Operationen: i lesen, inkrementieren und auf i schreiben.