日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java中Locks的使用

發(fā)布時間:2024/2/28 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中Locks的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • Lock和Synchronized Block的區(qū)別
    • Lock interface
    • ReentrantLock
    • ReentrantReadWriteLock
    • StampedLock
    • Conditions

java中Locks的使用

之前文章中我們講到,java中實現同步的方式是使用synchronized block。在java 5中,Locks被引入了,來提供更加靈活的同步控制。

本文將會深入的講解Lock的使用。

Lock和Synchronized Block的區(qū)別

我們在之前的Synchronized Block的文章中講到了使用Synchronized來實現java的同步。既然Synchronized Block那么好用,為什么會引入新的Lock呢?

主要有下面幾點區(qū)別:

  • synchronized block只能寫在一個方法里面,而Lock的lock()和unlock()可以分別在不同的方法里面。
  • synchronized block 不支持公平鎖,一旦鎖被釋放,任何線程都有機會獲取被釋放的鎖。而使用 Lock APIs則可以支持公平鎖。從而讓等待時間最長的線程有限執(zhí)行。
  • 使用synchronized block,如果線程拿不到鎖,將會被Blocked。 Lock API 提供了一個tryLock() 的方法,可以判斷是否可以獲得lock,這樣可以減少線程被阻塞的時間。
  • 當線程在等待synchronized block鎖的時候,是不能被中斷的。如果使用Lock API,則可以使用 lockInterruptibly()來中斷線程。
  • Lock interface

    我們來看下Lock interface的定義, Lock interface定義了下面幾個主要使用的方法:

    • void lock() - 嘗試獲取鎖,如果獲取不到鎖,則會進入阻塞狀態(tài)。
    • void lockInterruptibly() - 和lock()很類似,但是它可以將正在阻塞的線程中斷,并拋出java.lang.InterruptedException。
    • boolean tryLock() – 這是lock()的非阻塞版本,它回嘗試獲取鎖,并立刻返回是否獲取成功。
    • boolean tryLock(long timeout, TimeUnit timeUnit) – 和tryLock()很像,只是多了一個嘗試獲取鎖的時間。
    • void unlock() – unlock實例。
    • Condition newCondition() - 生成一個和當前Lock實例綁定的Condition。

    在使用Lock的時候,一定要unlocked,以避免死鎖。所以,通常我們我們要在try catch中使用:

    Lock lock = ...; lock.lock(); try {// access to the shared resource } finally {lock.unlock(); }

    除了Lock接口,還有一個ReadWriteLock接口,在其中定義了兩個方法,實現了讀鎖和寫鎖分離:

    • Lock readLock() – 返回讀鎖
    • Lock writeLock() – 返回寫鎖

    其中讀鎖可以同時被很多線程獲得,只要不進行寫操作。寫鎖同時只能被一個線程獲取。

    接下來,我們幾個Lock的常用是實現類。

    ReentrantLock

    ReentrantLock是Lock的一個實現,什么是ReentrantLock(可重入鎖)呢?

    簡單點說可重入鎖就是當前線程已經獲得了該鎖,如果該線程的其他方法在調用的時候也需要獲取該鎖,那么該鎖的lock數量+1,并且允許進入該方法。

    不可重入鎖:只判斷這個鎖有沒有被鎖上,只要被鎖上申請鎖的線程都會被要求等待。實現簡單

    可重入鎖:不僅判斷鎖有沒有被鎖上,還會判斷鎖是誰鎖上的,當就是自己鎖上的時候,那么他依舊可以再次訪問臨界資源,并把加鎖次數加一。

    我們看下怎么使用ReentrantLock:

    public void perform() {lock.lock();try {counter++;} finally {lock.unlock();}}

    下面是使用tryLock()的例子:

    public void performTryLock() throws InterruptedException {boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);if(isLockAcquired) {try {counter++;} finally {lock.unlock();}}}

    ReentrantReadWriteLock

    ReentrantReadWriteLock是ReadWriteLock的一個實現。上面也講到了ReadWriteLock主要有兩個方法:

    • Read Lock - 如果沒有線程獲得寫鎖,那么可以多個線程獲得讀鎖。
    • Write Lock - 如果沒有其他的線程獲得讀鎖和寫鎖,那么只有一個線程能夠獲得寫鎖。

    我們看下怎么使用writeLock:

    Map<String,String> syncHashMap = new HashMap<>();ReadWriteLock lock = new ReentrantReadWriteLock();Lock writeLock = lock.writeLock();public void put(String key, String value) {try {writeLock.lock();syncHashMap.put(key, value);} finally {writeLock.unlock();}}public String remove(String key){try {writeLock.lock();return syncHashMap.remove(key);} finally {writeLock.unlock();}}

    再看下怎么使用readLock:

    Lock readLock = lock.readLock();public String get(String key){try {readLock.lock();return syncHashMap.get(key);} finally {readLock.unlock();}}public boolean containsKey(String key) {try {readLock.lock();return syncHashMap.containsKey(key);} finally {readLock.unlock();}}

    StampedLock

    StampedLock也支持讀寫鎖,獲取鎖的是會返回一個stamp,通過該stamp來進行釋放鎖操作。

    上我們講到了如果寫鎖存在的話,讀鎖是無法被獲取的。但有時候我們讀操作并不想進行加鎖操作,這個時候我們就需要使用樂觀讀鎖。

    StampedLock中的stamped類似樂觀鎖中的版本的概念,當我們在
    StampedLock中調用lock方法的時候,就會返回一個stamp,代表鎖當時的狀態(tài),在樂觀讀鎖的使用過程中,在讀取數據之后,我們回去判斷該stamp狀態(tài)是否變化,如果變化了就說明該stamp被另外的write線程修改了,這說明我們之前的讀是無效的,這個時候我們就需要將樂觀讀鎖升級為讀鎖,來重新獲取數據。

    我們舉個例子,先看下write排它鎖的情況:

    private double x, y;private final StampedLock sl = new StampedLock();void move(double deltaX, double deltaY) { // an exclusively locked methodlong stamp = sl.writeLock();try {x += deltaX;y += deltaY;} finally {sl.unlockWrite(stamp);}}

    再看下樂觀讀鎖的情況:

    double distanceFromOrigin() { // A read-only methodlong stamp = sl.tryOptimisticRead();double currentX = x, currentY = y;if (!sl.validate(stamp)) {stamp = sl.readLock();try {currentX = x;currentY = y;} finally {sl.unlockRead(stamp);}}return Math.sqrt(currentX * currentX + currentY * currentY);}

    上面使用tryOptimisticRead()來嘗試獲取樂觀讀鎖,然后通過sl.validate(stamp)來判斷該stamp是否被改變,如果改變了,說明之前的read是無效的,那么需要重新來讀取。

    最后,StampedLock還提供了一個將read鎖和樂觀讀鎖升級為write鎖的功能:

    void moveIfAtOrigin(double newX, double newY) { // upgrade// Could instead start with optimistic, not read modelong stamp = sl.readLock();try {while (x == 0.0 && y == 0.0) {long ws = sl.tryConvertToWriteLock(stamp);if (ws != 0L) {stamp = ws;x = newX;y = newY;break;}else {sl.unlockRead(stamp);stamp = sl.writeLock();}}} finally {sl.unlock(stamp);}}

    上面的例子是通過使用tryConvertToWriteLock(stamp)來實現升級的。

    Conditions

    上面講Lock接口的時候有提到其中的一個方法:

    Condition newCondition();

    Condition提供了await和signal方法,類似于Object中的wait和notify。

    不同的是Condition提供了更加細粒度的等待集劃分。我們舉個例子:

    public class ConditionUsage {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length)notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}} }

    上面的例子實現了一個ArrayBlockingQueue,我們可以看到在同一個Lock實例中,創(chuàng)建了兩個Condition,分別代表隊列未滿,隊列未空。通過這種細粒度的劃分,我們可以更好的控制業(yè)務邏輯。

    本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/Locks

    更多精彩內容且看:

    • 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續(xù)更新
    • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
    • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續(xù)更新
    • java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細文章教程

    更多文章內容,請參考http://www.flydean.com/java-locks/

    總結

    以上是生活随笔為你收集整理的java中Locks的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。