A safety property is a property that something bad is not happening. A system is safe if nothing bad ever happens.
A race condition (defined strictly) is when two threads access the same mutable state concurrently and at least one is modifying the state. We prevent race conditions through the following two principles:
An atomicity violation generally is where a series of concurrent accesses to state leave it in a state that could not be achieved if all the actions were considered atomic (serialized). Atomicity violations can thus be seen as examples of race conditions (defined broadly). For our purposes, an atomicity violation is using information acquired in a synchronization block after the block is finished to perform some action on the state, when the information could be incorrect because of actions in a concurrent thread. Atomicity violations can be prevented by:
A liveness property is one that asserts that something good will eventually happen. A system is live as long as there is a chance of the goals being met.
A severe liveness violation is deadlock when all threads are stopped while waiting for another thread to release a resource. A related state is ``livelock'' when no threads make any progress; they continually wake, attempt to get a resource, give up, wait for a while and try again. It is the ``busy wait'' equivalent of deadlock. Deadlock can be avoided by ordering resources, in particular:
Starvation occurs when some thread never gets a chance to make progress. In order to prevent starvation, it is important not to engage in arbitrarily long computations while holding on to a resource:
These properties are not enforced by the Java compiler, but should be documented so that a programmer can determine whether they are met.