熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

關於JAVA多線程並發synchronized的測試與合理使用

2013-11-23 19:51:59  來源: Java高級技術 

  在項目開發中 或許會碰到JAVA的多線程處理 為保證業務數據的正常 必須加上鎖機制  常用的處理方法一般是加上synchronized關鍵字 目前JDK版本對synchronized已經做了很好的優化  我們不用再考慮其性能  但在實際使用中  往往由於處理不當  導致系統性能的嚴重下降 那麼該如何合理的使用synchronized  必須對其使用方式有個全面了解 在網上搜尋的資料 給出的是四種使用方式 其實可總結為兩種 一個是同步代碼塊 一個是同步方法體 那麼該如何使用 請看下面的測試

  准備兩個方法  對同一個變量做加法 再對每個方法 分別開十個線程執行

  [java]

  public class ThreadUnit

  {

  private int i = ;

  private Object obj = new Object()

  private Object obj = new Object()

  public synchronized Integer doAdd(Long start) throws Exception

  {

  Threadsleep(

  ++i;

  Threadsleep(

  return i;

  }

  public Integer doAdd(Long start) throws Exception

  {

  Threadsleep(

  ++i;

  Threadsleep(

  return i;

  }

  }

  相關代碼

  [java]

  // 十個線程同時執行方法

  for (int i = ; i < ; i++)

  {

  new Thread(new MessageThread( threadUnit))start()

  }

  // 十個線程同時執行方法

  for (int j = ; j < ; j++)

  {

  new Thread(new MessageThread( threadUnit))start()

  }

  線程處理

  [java]

  public void run()

  {

  try

  {

  if (operate ==

  {

  long start = SystemcurrentTimeMillis()

  int i = threadUnitdoAdd(start)

  long takeTime = SystemcurrentTimeMillis() start;

  Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms

  spendTime += takeTime;

  }

  else

  {

  long start = SystemcurrentTimeMillis()

  int i = threadUnitdoAdd(start)

  long takeTime = SystemcurrentTimeMillis() start;

  Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms

  spendTime += takeTime;

  }

  }

  catch (Exception e)

  {

  eprintStackTrace()

  }

  }

  運行結果

   在兩個方法體上都加上synchronized

  [java]

  public synchronized Integer doAdd(Long start) throws Exception

  [java]

  public synchronized Integer doAdd(Long start) throws Exception

  執行結果

  [html]

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  都是有序執行 變量值沒有產生錯亂 但花費時間ms

  在doAdd方法上加上synchronized doAdd不加

  [java]

  public synchronized Integer doAdd(Long start) throws Exception

  執行結果

  [java]

  doAdd方法加上synchronized:

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  doAdd方法瞬間執行完成 之後doAdd方法則是串行有序執行 這時doAdd方法獲取的變量值已經錯亂  doAdd獲取的正常  花費時間ms

   兩個方法在都沒使用synchronized前的情況

  執行結果

  [java]

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  可以看到 兩個方法的變量值獲取已經錯亂  但花費時間最少ms

   使用同步塊 在兩個方法內采用不同的對象鎖

  doAdd:

  [java]

  synchronized (obj

  {

  Threadsleep(

  ++i;

  Threadsleep(

  return i;

  }

  doAdd:

  [java]

  synchronized (obj

  {

  Threadsleep(

  ++i;

  Threadsleep(

  return i;

  }

  執行結果

  [html]

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  兩個方法有序交替執行 互不影響  花費時間ms 相對加鎖同一對象執行的時間縮短

   使用同步塊 使用方法參數作為對象鎖

  [java]

  public Integer doAdd(Long start) throws Exception

  {

  synchronized (start)

  {

  Threadsleep(

  ++i;

  Threadsleep(

  return i;

  }

  }

  執行結果

  [java]

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  執行效果和第三種情況相同  每個參數作為不同的對象 即便加上synchronized也不能起到鎖的效果

   把調用的類改為靜態類 只在一個方法上加鎖

  加鎖doAdd方法

  [java]

  public static synchronized Integer doAdd(Long start) throws Exception

  執行結果

  [html]

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  doAdd() => i= spendTime=ms

  花費時間ms

  和第二種情形類似  沒有加鎖的doAdd方法瞬間執行完成  doAdd方法則是串行有序執行

  總結

   synchronized關鍵在於鎖定的對象 如果是同一對象 那麼所有執行線程 必須等待對象鎖釋放後才能執行  如果是不同對象  那麼只對各對象所關聯的線程生效

   synchronized若加在方法體上  默認鎖定的是對象本身 對於所有加鎖的方法  都是按照串行規則有序執行  對於沒有加鎖的方法 不受任何影響  靜態類同理

   合理使用synchronized 既要保證穩定性 又要保證性能 需要在兩者間作出權衡  盡量把synchronized范圍細度化 合理控制業務處理流程  對象操作原子化 減少鎖的使用

  不要盲目在方法體上加synchronized關鍵字 如果每個方法負責處理的是不同業務  那麼盡量采用第四種情形 使用不同的對象鎖處理 而不是鎖定整個對象


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27586.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.