主程序運行1000個子線程(太少了結果不容易出來),每個子線程執行指向同一整數引用的i++,當1000個子線程運行完畢后,主線程繼續運行,輸出最終的i值。很顯然,如果最終輸出的結果i值不等于1000,那么中間i++操作一定被分解了。程序代碼如下:
【版本一】
import cn.yuzhe.multi.util.AllFinished;


public class ThreadSafeClass
{


public static void main(String[] args)
{
//要創建的子線程數
int threadNum=1000;
//每個子線程都要引用的對象
A_Integer bb=new A_Integer();
//創建能判斷所有子線程是否結束的對象,用于保證主線程能在多有子線程都結束后再執行余下的代碼,
//防止主線程提前于子線程結束
AllFinished af=new AllFinished(threadNum);
//創建多個子線程對象
NoAtomicIntegerThread[] at=new NoAtomicIntegerThread[threadNum];

for(int i=0;i<threadNum;i++)
{
at[i]=new NoAtomicIntegerThread(bb,i,af);
}

for(int i=0;i<threadNum;i++)
{
at[i].start();
}

while(true)
{

if( af.isAllFinished() )
{
System.out.println("主線程運行結束,應該獲得的最終值為"+threadNum
+";實際最終值為"+bb.int_I);
break;
}
int sleep=500; //睡眠一段時間,釋放時間片

try
{
Thread.sleep(sleep);

} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}


class NoAtomicIntegerThread extends Thread
{
public A_Integer jj;
private int id;
private AllFinished af;


public void run()
{
jj.int_I++;
af.setItemFinished(id);
// System.out.println(jj.int_I); //輸出中間結果
}


public NoAtomicIntegerThread(A_Integer __j,int _id,AllFinished _af)
{
super();
this.jj=__j;
this.id=_id;
this.af=_af;
}
}

class A_Integer


{
public int int_I=0;
}


這里要用到一個我自己定義的util類:

/** *//**
* @author 紅樓無夢,JAVA多線程QQ群:34237757
* Date:2008-8-13 09:28
* Function: 主線程創建多個分線程,保證主線程在所有分線程都結束后才能運行余下的代碼,直至結束。
*/

public class AllFinished
{
private boolean[] isItemsFinished;
private int num;


public AllFinished(int itemNum)
{
super();
num=itemNum;
isItemsFinished=new boolean[num];
for(int i=0;i<num;i++)
isItemsFinished[i]=false;
}

public synchronized boolean setItemFinished(int i)

{
if(i>=num)
return false;
this.isItemsFinished[i]=true;
return true;
}

public synchronized boolean isAllFinished()

{

for(int i=0;i<num;i++)
{
if(!this.isItemsFinished[i])
return false;
}
return true;
}
}

例子需要運行多次才能看到結果,當實際結果和理想結果不一樣的時候,很顯然,i++被分解了,結果的部分輸入如下:
......
996
997
998
主線程運行結束,應該獲得的最終值為1000;實際最終值為998。
=====================================================
【改進一】下面的代碼用AtomicInteger進行了改進,使得i++操作被原子化,代碼如下:

public class ThreadSafeClass
{


public static void main(String[] args)
{
//要創建的子線程數
int threadNum=1000;
//每個子線程都要引用的對象
AtomicInteger bb=new AtomicInteger(0);
//創建能判斷所有子線程是否結束的對象,用于保證主線程能在多有子線程都結束后再執行余下的代碼,
//防止主線程提前于子線程結束
AllFinished af=new AllFinished(threadNum);
//多個子線程對象
AtomicIntegerThread[] at=new AtomicIntegerThread[threadNum];

for(int i=0;i<threadNum;i++)
{
at[i]=new AtomicIntegerThread(bb,i,af);
}

for(int i=0;i<threadNum;i++)
{
at[i].start();
}

while(true)
{

if(af.isAllFinished())
{
System.out.println("主線程運行結束,應該獲得的最終值為"+threadNum
+";實際最終值為"+bb);
break;
}
int sleep=(int)(Math.random()*500);

try
{
Thread.sleep(sleep);

} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}


class AtomicIntegerThread extends Thread
{
private int id;
private AllFinished af;
public AtomicInteger j;


public AtomicIntegerThread(AtomicInteger __j,int _id,AllFinished _af)
{
super();
this.j=__j;
this.id=_id;
this.af=_af;
}



public void run()
{
j.getAndIncrement();
af.setItemFinished(id);
System.out.println(j); //這里輸出沒有同步,很可能會出現不一致,這里僅僅用來測試一下,正好能證明線程將操作分解^_^
}
}


運行了多次沒有出現被分解的情況,最后我把線程數從一千改成一萬,又增加到十萬,并且運行多次,沒有出現結果和預計結果不一致的情況。十萬個線程啊!如果能分解的話早把程序分得七零八碎了,呵呵。某次結果如下:
......
99994
99993
99992
主線程運行結束,應該獲得的最終值為100000;實際最終值為100000
=====================================================
【改進二】群友TITAN的方法更簡單,在版本一的基礎上加上一小段代碼

class NoAtomicIntegerThread extends Thread
{





public void run()
{

synchronized(jj)
{
jj.int_I++;
}
af.setItemFinished(id);
System.out.println(jj.int_I);
}




}


我對比了一下改進一和改進二,在十萬個線程并發情況下,二者的運行速度幾乎沒有差別。可見JAVA類庫中的AtomicInteger還是很實用的。
大伙有什么改進的方法,歡迎大家提意見。yuzhe80@126.com
******************************************************************************
后話:這里為了保證主線程在子線程都執行完后再繼續執行,特意定義了一個類AllFinished,記錄每個子線程是否結束,其實大可不必,因為JAVA中對線程有join函數,在main函數中改成這樣就可以了。

public class ThreadSafeClass
{

public static void main(String[] args)
{
//要創建的子線程數
int threadNum=1000;
//每個子線程都要引用的對象
AtomicInteger bb=new AtomicInteger(0);
//多個子線程對象
AtomicIntegerThread[] at=new AtomicIntegerThread[threadNum];

for(int i=0;i<threadNum;i++)
{
at[i]=new AtomicIntegerThread(bb,i);
}
long last=System.currentTimeMillis();

for(int i=0;i<threadNum;i++)
{
at[i].start();
}

for(int i=0;i<threadNum;i++)
{

try
{
at[i].join(); //保證主線程在所有子線程結束后再執行

} catch (InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("主線程運行結束,應該獲得的最終值為"+threadNum
+";實際最終值為"+bb+"程序運行時間"+(System.currentTimeMillis()-last)+"毫秒");

}
}


而且這樣修改,在性能上有很大提升,用我自定義的類AllFinished,運行1000個線程,平均時間為2100ms,而用join函數,平均時間為1600ms,性能提升了25%。以后還是推薦大伙使用join吧^_^