qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Java多線程程序非阻塞式鎖定實現

            Java對多線程程序的鎖定已經有良好的支持,通常使用synchronized修飾一個方法或者一段代碼。但是有一個問題,多個線程同時調用同一個方法的時候,所有線程都被排隊處理了。該被調用的方法越耗時,線程越多的時候,等待的線程等待的時間也就越長,甚至于幾分鐘或者幾十分鐘。對于Web等對反應時間要求很高的系統來說,這是不可以接受的。本文就介紹一種自己實現的鎖定方法,可以在沒有拿到鎖之后馬上返回,告訴客戶稍候重試。

            某一段程序同一時刻需要保證只能單線程調用,那么策略很簡單,最先到的線程獲取鎖成功,在它釋放之前其它線程都會獲取失敗。首先要構造一個全局的系統鎖倉庫,代碼如下:

          /*
           * LockStore.java  2012-5-15
           */

          import java.util.Date;
          import java.util.HashMap;
          import java.util.Map;

          /**
           * 公用的內存鎖倉庫. 分為獲取鎖和釋放鎖兩種操作。
           *
           * @version 1.0
           */
          public final class LockStore {
           // volatile保證所有線程看到的鎖相同
           private static volatile Map<String, Date> locks = new HashMap<String, Date>();

           private LockStore() {

           }

           /**
            * 根據鎖名獲取鎖
            *
            * @param lockName
            *            鎖名
            * @return 是否鎖定成功
            */
           public synchronized static Boolean getLock(String lockName) {
            Boolean locked = false;

            if (StringUtils.isEmpty(lockName)) {
             throw new RuntimeException("Lock name can't be empty");
            }

            Date lockDate = locks.get(lockName);
            if (lockDate == null) {
             locks.put(lockName, new Date());
             locked = true;
            }

            return locked;
           }

           /**
            * 根據鎖名釋放鎖
            *
            * @param lockName
            *            鎖名
            */
           public synchronized static void releaseLock(String lockName) {
            if (StringUtils.isEmpty(lockName)) {
             throw new RuntimeException("Lock name can't be empty");
            }

            Date lockDate = locks.get(lockName);
            if (lockDate != null) {
             locks.remove(lockName);
            }
           }

           /**
            * 獲取上次成功鎖定的時間
            *
            * @param lockName
            *            鎖名
            * @return 如果還沒有鎖定返回NULL
            */
           public synchronized static Date getLockDate(String lockName) {
            if (StringUtils.isEmpty(lockName)) {
             throw new RuntimeException("Lock name can't be empty");
            }

            Date lockDate = locks.get(lockName);

            return lockDate;
           }
          }



            鎖倉庫提供了三個方法,都是靜態的,可以在系統內任意地方調用。 這里要提的是鎖名,是一個字符串,可以隨意構造,通常是需要鎖定的方法名+需要單線程處理的標識。比如部門ID。這樣不同的部門有不同的鎖,獨立運行,同一個部門同一個鎖,單線程處理。具體使用如下:

          /*
           * LockTest.java  2012-6-19
           */

          import java.text.SimpleDateFormat;
          import java.util.Date;

          /**
           * 鎖倉庫的使用
           * 
           * @version 1.0
           */
          public class LockTest {
           public Boolean doSomething(String departmentId, StringBuffer message) {
            // 同一個部門同時只能有一個處理, 不同部門可以并行處理
            String lockName = "doSomething_" + departmentId;
            Boolean result;
            if (LockStore.getLock(lockName)) {
             try {
              // do things here
             } finally {
              LockStore.releaseLock(lockName);
              result = true;
             }
            } else {
             Date lastLockDate = LockStore.getLockDate(lockName);
             String messageStr = "您所在的部門已經在處理中, 啟動時間為:"
               + getDateDetailDesc(lastLockDate);
             message.append(messageStr);
             result = false;
            }

            return result;
           }

           /*
            * 獲取日期的具體時間描述
            */
           private String getDateDetailDesc(Date date) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            return sdf.format(date);
           }
          }

            通過以上設計,系統內部任何耗時且需要保證單線程的地方都可以用該方法實現非阻塞式的訪問,提高用戶體驗。甚至于有的調用本身就要求這樣的設計,只需處理一次,比如做日終。鎖名的自定義帶來了鎖粒度的靈活設定,可以在運行時根據參數實現任意級別的鎖定。

          posted on 2012-06-21 09:50 順其自然EVO 閱讀(1068) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2012年6月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 连江县| 彰武县| 晋中市| 原阳县| 濮阳市| 渭源县| 朝阳市| 鲜城| 瑞昌市| 乐昌市| 若尔盖县| 中阳县| 东山县| 普兰店市| 静宁县| 健康| 柞水县| 汶川县| 长沙县| 岑溪市| 登封市| 灌南县| 前郭尔| 拉孜县| 会同县| 临泉县| 特克斯县| 兴海县| 平潭县| 敦煌市| 巴彦淖尔市| 湖州市| 平罗县| 松溪县| 道孚县| 兴安县| 乳源| 凤翔县| 苗栗市| 孟连| 体育|