What is the purpose of volatile?

The volatile keyword in Java is used in multithreading. Unlike volatile in C++, it doesn't necessarily do anything with the processor's cache. It has exactly two effects on an object's field.

Firstly, reads and writes to such a field become atomic. This application is relevant only for long and double types, and not on all platforms. For other types of fields they are atomic anyway.

The second and more interesting effect is that a pair of write-read events for such a field acts as synchronization actions. This establishes a happens-before relationship between them. This means there is a guarantee that what happens in memory before the write will be visible after the read. Thus, values written to other variables will be successfully read.

For a full understanding of the topic, the documentation is recommended for reading. The effect of volatile is best illustrated by a problem, often used as a question itself. The interviewer asks what the following code will print:
int a; int b;

// thread 1:
a = 1;
b = 2;

// thread 2:
System.out.print(b);
System.out.print(a);

The trick here is that in addition to the obvious outputs of 21 (thread 2 executed after thread 1), 00 (thread 2 executed before thread 1, variables not yet initialized), and 01 (thread 2 executed between writes), there could also be an unexpected output of 20. This occurs because the program order guarantees at least the visibility of the correct sequence of operations within a single thread. However, a happens-before "bridge" is needed for order between threads. It is achieved by simply applying volatile modifier to variable b. The unexpected output of 20 would be eliminated.

This effect is used to obtain a simple and cost-effective adaptation of programs to a multithreaded environment without using complex and error-prone techniques of locks and synchronization.