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


public class ThreadSafeClass
{


public static void main(String[] args)
{
//要?jiǎng)?chuàng)建的子線程數(shù)
int threadNum=1000;
//每個(gè)子線程都要引用的對(duì)象
A_Integer bb=new A_Integer();
//創(chuàng)建能判斷所有子線程是否結(jié)束的對(duì)象,用于保證主線程能在多有子線程都結(jié)束后再執(zhí)行余下的代碼,
//防止主線程提前于子線程結(jié)束
AllFinished af=new AllFinished(threadNum);
//創(chuàng)建多個(gè)子線程對(duì)象
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("主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為"+threadNum
+";實(shí)際最終值為"+bb.int_I);
break;
}
int sleep=500; //睡眠一段時(shí)間,釋放時(shí)間片

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); //輸出中間結(jié)果
}


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;
}


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

/** *//**
* @author 紅樓無夢(mèng),JAVA多線程QQ群:34237757
* Date:2008-8-13 09:28
* Function: 主線程創(chuàng)建多個(gè)分線程,保證主線程在所有分線程都結(jié)束后才能運(yùn)行余下的代碼,直至結(jié)束。
*/

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;
}
}

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

public class ThreadSafeClass
{


public static void main(String[] args)
{
//要?jiǎng)?chuàng)建的子線程數(shù)
int threadNum=1000;
//每個(gè)子線程都要引用的對(duì)象
AtomicInteger bb=new AtomicInteger(0);
//創(chuàng)建能判斷所有子線程是否結(jié)束的對(duì)象,用于保證主線程能在多有子線程都結(jié)束后再執(zhí)行余下的代碼,
//防止主線程提前于子線程結(jié)束
AllFinished af=new AllFinished(threadNum);
//多個(gè)子線程對(duì)象
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("主線程運(yùn)行結(jié)束,應(yīng)該獲得的最終值為"+threadNum
+";實(shí)際最終值為"+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); //這里輸出沒有同步,很可能會(huì)出現(xiàn)不一致,這里僅僅用來測(cè)試一下,正好能證明線程將操作分解^_^
}
}


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

class NoAtomicIntegerThread extends Thread
{





public void run()
{

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




}


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

public class ThreadSafeClass
{

public static void main(String[] args)
{
//要?jiǎng)?chuàng)建的子線程數(shù)
int threadNum=1000;
//每個(gè)子線程都要引用的對(duì)象
AtomicInteger bb=new AtomicInteger(0);
//多個(gè)子線程對(duì)象
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(); //保證主線程在所有子線程結(jié)束后再執(zhí)行

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

}
}


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