The Java memory model describes the communication between the memory of the threads and the main memory, e.g. then are changes of threads visible to others and then does a thread re-fresh its own memory from the main memory.
It also describes which operations are atomic and the ordering of operations.
An atomic operation is an operation which is performed as a single unit of work without the possibility of interference from other operations.
In Java the language specification guarantees that that reading or writing a variable is atomic (unless the variable is of type long or double). Long and double are only atomic if they declared as volatile.
The operation i++ it not atomic in Java for the standard variables (int, long, etc). It first reads the value which is currently stored in i (atomic operations) and then it adds one to it (atomic operation). But between the read and the write the value of i might have changed. Java
Since Java 1.5 the java language provides atomic variables, e.g. AtomicInteger or AtomicLong which provide methods like getAndDecrement(), getAndIncrement() and getAndSet() which are atomic.
For variables which are protected by synchronized it it guaranteed by the Java memory model that each thread entering a synchronized block of code sees the effects of all previous modifications that were guarded by the same lock.