>>811
コンパイラ視点で見れば中身のわからないcond.wait()と言う関数呼び出しが
グローバル変数runningに対する副作用を持たない(値を書き換えない)ことの保証が無いから、
cond.wait()をループ外にくくりだす最適化が行われることは普通は無い。 --- (A)
また、ソースコード上cond.wait()を呼び出した後にrunningを参照する箇所があれば、
普通はかならずメモリからrunningを読み直すコードが吐かれる --- (B)

普通でない場合というのはコンパイラがcond.wait()メソッドの中身まで知っていて
runningに対する副作用が無いと結論付ける場合が考えられるが、
それでもcond.wait()の中で
 (1) メモリバリアを行っており、
 (2) その意味をコンパイラが知っている
限り、コンパイラが「(cond.wait()呼び出しによる)runningに対する副作用が無い」と結論付けることはありえない --- (C)

というわけで、普通は(A)、(B)が成立するからrunningのvolatileは不要
(A)、(B)非成立な変に賢いコンパイラでも、(1)と(2)が成立するなら(C)が成立するからrunningのvolatileは不要