雖然搞JAVA好多年,一直沒有搞明白同步Serializable,閒來無事,做幾個小程序測試一下多線程計算一個靜態數:
下面的代碼是我經過修改後的最終版代碼。
先創建一個Persons ,用了單例模式,SET和GET方法都做了Serializable,輸出方法放在單例的Person裏並且做了同步,無論如何限制get方法都會有輸出重複的問題,但是有一個現象,就是儘管數據有重複,但是所有的重複後就會跳過重複的數,如1,2,2,4這樣的效果,最後我分析,只要程序做了單例,計算的方法是有Serializable的,其實這個變量都是遞增的,之所以取出來的數據會重複,完全是因爲取數據的方法取的是對象內存變量,而在多線程執行的時候,一個對象的存和取並不是同步的。
/**
* @author huang.yueyong
* @date 2010-8-15
*
*/
package test;
import java.io.Serializable;
/**
* @author huangyy
*
*/
public class Persons implements Serializable{
int flag=0;
private static Persons instant=null;
private Persons(){
}
/**
* @return the flag
*/
public synchronized int getFlag() {
return this.flag;
}
// /**
// * @param flag the flag to set
// */
public synchronized void setFlag(int flag) {
System.out.println("輸入Flag:"+flag);
this.flag = flag;
}
public static Persons getPerson(){
if(instant==null){
instant=new Persons();
System.out.println("Person init!");
}
return instant;
}
}
/**
* @author huang.yueyong
* @date 2010-8-13
*
*/
package test;
/**
* @author huangyy
*
*/
public class Thread1 implements Runnable {
/**
* @param args
*/
public void run() {
while(true){
Persons per=Persons.getPerson();
per.setFlag(per.getFlag()+1);
System.out.println("線程1:"+per.getFlag());
try {
Thread.sleep(1*10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* @author huang.yueyong
* @date 2010-8-13
*
*/
package test;
/**
* @author huangyy
*
*/
public class Thread2 implements Runnable {
/**
* @param args
*/
public static void main(String[] args){
Thread1 st1=new Thread1();
Thread2 st2=new Thread2();
Thread tr1=new Thread(st1);
Thread tr2=new Thread(st2);
tr1.start();
tr2.start();
}
public void run() {
Persons per=Persons.getPerson();
while(true){
if(per.getFlag()>100){
System.exit(0);
}
per.setFlag(per.getFlag()+1);
System.out.println("線程2:"+per.getFlag());
try {
Thread.sleep(1*10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
用這個測試方法,發現單看輸入的值一直都是正確的,可是輸出時候雖然做了同步,但是取出來的數據仍然會有重複的情況,說明同步其實主要是針對方法而言,針對對象的同步其實沒有多大的實際意義。
這個實驗告訴我,我們在對變量計算的時候,如果確實需要同步,業務直接在這一個方法裏完成,如果用到其它方法,需要在這個方法裏,把變量當參數傳出去,不要指望這個對像爲你保存場景。