volatileで排他制御出来ると、いつから思ってた？ atomicやsynchronized使うべし

久々に volatileが使われているソース
しかも使い方間違ってて、ちゃんと同期出来てないものに
出会ったので、確認コード

複数のスレッドから、同じカウンターをインクリメントするサンプル

```java:test.java
package test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

public class Sync {
	private final int THREAD_NUM = 50;
	private final int COUNT_NUM = 1000;
	
	private static Sync instance = new Sync();
	
	
	private int mCounter=0;
	private volatile int mVolatileCounter=0;
	private Object mSyncObj = new Object();
	private AtomicInteger mAtomCounter = new AtomicInteger(0);
	
    public static void main(String[] args) {
    	instance._run( "dummy", instance._no_sync );
    	instance.mCounter = 0;
    	instance._run( "_no_sync", instance._no_sync );
    	instance.mCounter = 0;
    	instance._run( "_synchronized", instance._synchronized );
    	instance._run( "_volatile", instance._volatile );
    	instance._run( "_atom", instance._atom );
    	instance.mAtomCounter.set(-1);
    	instance._run( "_lock_free", instance._lock_free );
    }
	
    
    private Runnable _no_sync	=        	
	    new Runnable(){
		    public void run() {
		        for (int i = 0; i < COUNT_NUM; i++) {
		            System.out.print( mCounter++ + ",");
		        }
		    }	
		};

    private Runnable _synchronized =
    	new Runnable(){
    	    public void run() {
    	        for (int i = 0; i < COUNT_NUM; i++) {
    	        	synchronized(mSyncObj){
    	        		System.out.print( mCounter++ + ",");
    	        	}
    	        }
    	    }
    	};
    
    private Runnable _volatile = 
    	new Runnable(){
		    public void run() {
		        for (int i = 0; i < COUNT_NUM; i++) {
	        		System.out.print( mVolatileCounter++ + ",");
		        }
		    }			    	    
		};
    		
	private Runnable _atom = 
        	new Runnable(){
	    public void run() {
	        for (int i = 0; i < COUNT_NUM; i++) {
        		System.out.print( mAtomCounter.getAndIncrement() + ",");	
	        }
	    }			    	    
	};
    	
	private Runnable _lock_free = 
        	new Runnable(){
	    public void run() {
	        for (int i = 0; i < COUNT_NUM; i++) {
	        	int n;
	        	do{
	        		n = mAtomCounter.get();
	        	}
	        	while(!mAtomCounter.compareAndSet(n, n+1));
                        // print前に他スレッドからcompareAndSetが呼ばれ、出力がずれるので修正
        		// System.out.print( mAtomCounter.get() + ",");	        		
        		System.out.print( n+1 + ",");	        		
        		
	        }
	    }			    	    
	};
    	
    	
    public void _run( String sMsg, Runnable runnable){

    	System.out.println( "[" + sMsg + "]  Start!!");    	

        long start = System.currentTimeMillis();
    	
    	ArrayList<Thread>	thread = new ArrayList<Thread>();
    	for( int i=0; i<THREAD_NUM; i++ ){
	        Thread tt = new Thread( runnable );
	        thread.add(tt);
	        tt.start();
    	}
        
    	for( Thread t : thread ){
    		try {
				t.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	
        System.out.println("\n" + sMsg + ": " + (System.currentTimeMillis() - start) + "ms");    	
    }
}
```

C++ゲンガーなので変な書き方だったらすみません。
まず、今回は コンソール出力が重いので 時間は無視して

#結果の見方
synchronized以外は、出力までatomic性を求めてないので
数値の順番はどうでもよい。
重複（抜け）があると、同期に問題がある

データを スレッド起動より500ms待機させ
よりスレッドの衝突がしやすいものにかえた
（asahina_devさんありがとうございます）
ので、スレッド数１０、ループ３回で差が出たので
そのデータにさしかえました

LockFreeがConsole出力前に他スレッドがカウンター書き換える可能性があるので
少し修正しました

同期しない: 
2,4,6,4,3,3,11,2,14,2,16,15,13,12,10,9,7,8,6,5,23,22,21,20,19,18,17,26,25,24,
重複、抜けがあります
抜け：0,1,27,28,29
重複：2,2,3,4,6,

synchronized:
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
パーフェクト！
もちろん出力までsynchronizedしてるので出力までAtomic

volatile:
0,2,0,4,5,1,0,6,3,8,7,9,12,14,13,10,11,19,18,17,16,15,24,23,22,21,20,25,26,27,
重複、抜けあり
抜け：28,29,30
重複：0,0,0,

atomic:
1,8,4,6,5,2,3,7,16,18,15,14,13,12,11,10,0,9,25,24,23,22,21,20,19,17,28,27,26,29,
重複データなし。Atomic性保たれてます

LockFree:
0,3,4,5,2,8,6,7,1,16,15,14,13,12,11,10,9,24,23,22,21,20,19,18,17,25,26,27,28,29,
atomicと同じく重複データなし。Atomic性保持。


#速度（参考）
データ量を１００倍、スレッド数２倍にして
Console出力命令を消し
各機能の10回平均

同期なし: 7ms
そりゃー速い！！


volatile: 180ms
速いけど、カウンターとして正しく動作しない


synchronized: 403ms
意外に速かった！！
カウンター以外の処理もAtomic性を保てるので
基本的に synchronized使えばよくね？

atomic: 1089ms
予想外に遅かった・・・
でも、条件によってはsynchronizedより速い事もある・・はず

lock_free: 1094ms
多分 getAndIncrement等は、8086系では少なくとも compareAndSet
で実装してるのでしょう
上記とだいたい同じ




#結論
volatileは同期されると思うな。volatileは基本 コンパイル最適か抑制。
同期したければ素直に synchronized 使う
Atomic系の処理は、よく考えて使おう。synchronizedの方が速いケースも多い


間違い指摘あったらおねがいします。