首頁  >  文章  >  Java  >  Java使用三種方法實現高並發鎖的範例程式碼

Java使用三種方法實現高並發鎖的範例程式碼

黄舟
黄舟原創
2017-08-22 10:12:561894瀏覽

本篇文章主要介紹了java高並發鎖的3種實作範例程式碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

初級技巧 - 樂觀鎖定

#樂觀鎖定適合這樣的場景:讀不會衝突,寫會衝突。同時讀的頻率遠大於寫。

以下面的程式碼為例,悲觀鎖定的實作:


public Object get(Object key) { 
  synchronized(map) { 
   if(map.get(key) == null) { 
     // set some values 
   } 
    return map.get(key); 
  } 
}

樂觀鎖定的實作:


public Object get(Object key) { 
  Object val = null; 
  if((val = map.get(key) == null) { 
    // 当map取值为null时再加锁判断 
    synchronized(map) { 
      if(val = map.get(key) == null) { 
        // set some value to map... 
      } 
    } 
  } 
  return map.get(key); 
}

中級技巧- String.intern()

樂觀鎖不能很好解決大量寫衝突問題,但是如果很多場景下,鎖實際上只是針對某個用戶或某個訂單。例如一個使用者必須先建立session,才能進行後面的操作。但是由於網路原因,創建用戶session的請求和後續請求幾乎同時達到,而並行線程可能會先處理後續請求。一般情況,需要為使用者sessionMap加上鎖,例如上面的樂觀鎖。在這種場景下,可以講鎖限定到使用者本身上,也就是從原來的


#
lock.lock();

  int num=storage.get(key);

  storage.set(key,num+1);

lock.unlock();

改為:


lock.lock(key);

  int num=storage.get(key);

  storage.set(key,num+1);

lock.unlock(key);

這個比較類似於資料庫表鎖和行鎖的概念,顯然行鎖的並發能力比表鎖高很多。

使用String.inter()是這種思路的一種具體實作。類別 String 維護一個字串池。 當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(該物件由 equals(Object) 方法決定),則傳回池中的字串。可見,當String相同時,String.intern()總是傳回同一個對象,因此就實作了對相同使用者加鎖。由於鎖的粒度局限於具體用戶,使系統獲得了最大程度的並發。


public void doSomeThing(String uid) { 
  synchronized(uid.intern()) { 
    // ... 
  } 
}

CopyOnWriteMap?

既然說到了“類似於資料庫中的行鎖的概念”,就不得不提一下MVCC,Java中CopyOnWrite類別實作了MVCC。 Copy On Write是這樣一種機制。當我們讀取共享資料的時候,直接讀取,不需要同步。當我們修改資料的時候,我們就把目前資料Copy一份副本,然後在這個副本 上進行修改,完成之後,再用修改後的副本,替換掉原來的資料。這種方法就叫做Copy On Write。

但是,,,JDK並沒有提供CopyOnWriteMap,為什麼?下面有個很好的回答,就是已經有了ConcurrentHashMap,為什麼還需要CopyOnWriteMap?

Fredrik Bromee 寫道

I guess this depends on your use case, but why would you need a CopyOnWriteMap when you already have a ConcurrentHashMap?##lain

For a plain lookup table with many readers and only one or few updates it is a good fit.

Compared to a copy on write collection:

Read concurrency:

Equal to a copy on write collection. Several readers can retrieve elements from the map concurrently in a lock-free fashion.

Write concurrency:

Better concurrency than the copy on write collections that basically serialize updates (one collections update serialize updates (one time). Using a concurrent hash map you have a good chance of doing several updates concurrently. If your hash keys are evenly distributed.

#If you do want to have the effect of a copyon write

If you do want to have the effect of a copy, on write

If you do want to have the effect of a copyon write map always initialize a ConcurrentHashMap with a concurrency level of 1.

高級技巧- 類別ConcurrentHashMap

String.inter()的缺陷是類別String 維護一個字串池是放在JVM perm區的,如果使用者數特別多,導致放入字串池的String不可控,有可能導致OOM錯誤或過多的Full GC。怎麼樣能控制鎖的個數,同時減少粒度鎖呢?直接使用Java ConcurrentHashMap?還是你想加入自己更精細的控制?那麼可以藉鏡ConcurrentHashMap的方式,將需要加鎖的物件分成多個bucket,每個bucket加上一個鎖,偽代碼如下:


##
Map locks = new Map(); 
List lockKeys = new List(); 
for(int number : 1 - 10000) { 
  Object lockKey = new Object(); 
  lockKeys.add(lockKey); 
  locks.put(lockKey, new Object()); 
}  
public void doSomeThing(String uid) { 
  Object lockKey = lockKeys.get(uid.hash() % lockKeys.size()); 
  Object lock = locks.get(lockKey); 
  synchronized(lock) { 
   // do something 
  } 
}

以上是Java使用三種方法實現高並發鎖的範例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn