關於JAVA的同步試驗

雖然搞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();
   }
  }
}
}

 

用這個測試方法,發現單看輸入的值一直都是正確的,可是輸出時候雖然做了同步,但是取出來的數據仍然會有重複的情況,說明同步其實主要是針對方法而言,針對對象的同步其實沒有多大的實際意義。

 

這個實驗告訴我,我們在對變量計算的時候,如果確實需要同步,業務直接在這一個方法裏完成,如果用到其它方法,需要在這個方法裏,把變量當參數傳出去,不要指望這個對像爲你保存場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章