幾種JAVA細部鎖定的實現方式_java

來源:互聯網
上載者:User

最近在工作上碰見了一些高並發的情境需要加鎖來保證商務邏輯的正確性,並且要求加鎖後效能不能受到太大的影響。初步的想法是通過資料的時間戳記,id等關鍵字來加鎖,從而保證不同類型資料處理的並發性。而java自身api提供的鎖粒度太大,很難同時滿足這些需求,於是自己動手寫了幾個簡單的擴充...

1. 分段鎖

        借鑒concurrentHashMap的分段思想,先產生一定數量的鎖,具體使用的時候再根據key來返回對應的lock。這是幾個實現裡最簡單,效能最高,也是最終被採用的鎖策略,代碼如下:

/** * 分段鎖,系統提供一定數量的原始鎖,根據傳入對象的雜湊值擷取對應的鎖並加鎖 * 注意:要鎖的對象的雜湊值如果發生改變,有可能導致鎖無法成功釋放!!! */public class SegmentLock<T> {  private Integer segments = 16;//預設分段數量  private final HashMap<Integer, ReentrantLock> lockMap = new HashMap<>();  public SegmentLock() {    init(null, false);  }  public SegmentLock(Integer counts, boolean fair) {    init(counts, fair);  }  private void init(Integer counts, boolean fair) {    if (counts != null) {      segments = counts;    }    for (int i = 0; i < segments; i++) {      lockMap.put(i, new ReentrantLock(fair));    }  }  public void lock(T key) {    ReentrantLock lock = lockMap.get((key.hashCode()>>>1) % segments);    lock.lock();  }  public void unlock(T key) {    ReentrantLock lock = lockMap.get((key.hashCode()>>>1) % segments);    lock.unlock();  }}

2. 雜湊鎖

        上述分段鎖的基礎上發展起來的第二種鎖策略,目的是實現真正意義上的細部鎖定。每個雜湊值不同的對象都能獲得自己獨立的鎖。在測試中,在被鎖住的代碼執行速度飛快的情況下,效率比分段鎖慢 30% 左右。如果有長耗時操作,感覺表現應該會更好。代碼如下:

public class HashLock<T> {  private boolean isFair = false;  private final SegmentLock<T> segmentLock = new SegmentLock<>();//分段鎖  private final ConcurrentHashMap<T, LockInfo> lockMap = new ConcurrentHashMap<>();  public HashLock() {  }  public HashLock(boolean fair) {    isFair = fair;  }  public void lock(T key) {    LockInfo lockInfo;    segmentLock.lock(key);    try {      lockInfo = lockMap.get(key);      if (lockInfo == null) {        lockInfo = new LockInfo(isFair);        lockMap.put(key, lockInfo);      } else {        lockInfo.count.incrementAndGet();      }    } finally {      segmentLock.unlock(key);    }    lockInfo.lock.lock();  }  public void unlock(T key) {    LockInfo lockInfo = lockMap.get(key);    if (lockInfo.count.get() == 1) {      segmentLock.lock(key);      try {        if (lockInfo.count.get() == 1) {          lockMap.remove(key);        }      } finally {        segmentLock.unlock(key);      }    }    lockInfo.count.decrementAndGet();    lockInfo.unlock();  }  private static class LockInfo {    public ReentrantLock lock;    public AtomicInteger count = new AtomicInteger(1);    private LockInfo(boolean fair) {      this.lock = new ReentrantLock(fair);    }    public void lock() {      this.lock.lock();    }    public void unlock() {      this.lock.unlock();    }  }}

3. 弱引用鎖

        雜湊鎖因為引入的分段鎖來保證鎖建立和銷毀的同步,總感覺有點瑕疵,所以寫了第三個鎖來尋求更好的效能和更細粒度的鎖。這個鎖的思想是藉助java的弱引用來建立鎖,把鎖的銷毀交給jvm的記憶體回收,來避免額外的消耗。

        有點遺憾的是因為使用了ConcurrentHashMap作為鎖的容器,所以沒能真正意義上的擺脫分段鎖。這個鎖的效能比 HashLock 快10% 左右。鎖代碼:

/** * 弱引用鎖,為每個獨立的雜湊值提供獨立的鎖功能 */public class WeakHashLock<T> {  private ConcurrentHashMap<T, WeakLockRef<T, ReentrantLock>> lockMap = new ConcurrentHashMap<>();  private ReferenceQueue<ReentrantLock> queue = new ReferenceQueue<>();  public ReentrantLock get(T key) {    if (lockMap.size() > 1000) {      clearEmptyRef();    }    WeakReference<ReentrantLock> lockRef = lockMap.get(key);    ReentrantLock lock = (lockRef == null ? null : lockRef.get());    while (lock == null) {      lockMap.putIfAbsent(key, new WeakLockRef<>(new ReentrantLock(), queue, key));      lockRef = lockMap.get(key);      lock = (lockRef == null ? null : lockRef.get());      if (lock != null) {        return lock;      }      clearEmptyRef();    }    return lock;  }  @SuppressWarnings("unchecked")  private void clearEmptyRef() {    Reference<? extends ReentrantLock> ref;    while ((ref = queue.poll()) != null) {      WeakLockRef<T, ? extends ReentrantLock> weakLockRef = (WeakLockRef<T, ? extends ReentrantLock>) ref;      lockMap.remove(weakLockRef.key);    }  }  private static final class WeakLockRef<T, K> extends WeakReference<K> {    final T key;    private WeakLockRef(K referent, ReferenceQueue<? super K> q, T key) {      super(referent, q);      this.key = key;    }  }} 

後記

    最開始想藉助 locksupport 和 AQS 來實現細部鎖定,寫著寫著發現正在實現的東西和java 原生的鎖區別不大,於是放棄改為對java內建鎖的封裝,浪費了不少時間。

    實際上在實現了這些細部鎖定之後,又有了新的想法,比如可以通過分段思想將資料提交給專門的線程來處理,可以減少大量線程的阻塞時間,留待日後探索...

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.