There are two conclusions from JLS:
Race conditions mean to let your program's output depend on who gets at a specific point first. For instance, if you have 2 threads: T1 and T2, if your programs output is X if T1 gets to point P in the program first and the program's output is Y if T2 gets to point P first, then you have a race condition.
In pseudocode:
Global variable i initialized to 6;
Thread 1:
aquire(lock l)
increment global variable i, i.e. i++;
Thread 2:
aquire(lock l)
double the value of global var i, i.e.: i*=2;
If T1 aquires the lock l firts and T2 second the value of i will be 14 If T2 aquires the lock l firts and T1 second the value of i will be 13