最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程中Lock的使用小結(jié)

 更新時間:2023年04月28日 16:05:36   作者:程序員萬萬  
jdk1.5 以后,提供了各種鎖,本文主要介紹了Java多線程中Lock的使用小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Jdk1.5 以后,在 java.util.concurrent.locks 包下,有一組實現(xiàn)線程同步的接口和類,說到線程的同步,可能大家都會想到 synchronized 關(guān)鍵字,

這是 java 內(nèi)置的關(guān)鍵字,用來處理線程同步的,但這個關(guān)鍵字有很多的缺陷,使用起來也不是很方便和直觀,所以就出現(xiàn)了 Lock,下面,我們

就來對比著講解 Lock。

通常我們在使用 synchronized 關(guān)鍵字的時候會遇到下面這些問題:

(1)不可控性,無法做到隨心的加鎖和釋放鎖。

(2)效率比較低下,比如我們現(xiàn)在并發(fā)的讀兩個文件,讀與讀之間是互不影響的,但如果給這個讀的對象使用 synchronized 來實現(xiàn)同步的話,

那么只要有一個線程進入了,那么其他的線程都要等待。

(3)無法知道線程是否獲取到了鎖。

而上面 synchronized 的這些問題,Lock 都可以很好的解決,并且 jdk1.5 以后,還提供了各種鎖,例如讀寫鎖,但有一點需要注意,使用 synchronized

關(guān)鍵時,無須手動釋放鎖,但使用 Lock 必須手動釋放鎖。下面我們就來學(xué)習(xí)一下 Lock 鎖。

Lock 是一個上層的接口,其原型如下,總共提供了 6 個方法:

public interface Lock {
  // 用來獲取鎖,如果鎖已經(jīng)被其他線程獲取,則一直等待,直到獲取到鎖
   void lock();
  // 該方法獲取鎖時,可以響應(yīng)中斷,比如現(xiàn)在有兩個線程,一個已經(jīng)獲取到了鎖,另一個線程調(diào)用這個方法正在等待鎖,但是此刻又不想讓這個線程一直在這死等,可以通過
    調(diào)用線程的Thread.interrupted()方法,來中斷線程的等待過程
  void lockInterruptibly() throws InterruptedException;
  // tryLock方法會返回bool值,該方法會嘗試著獲取鎖,如果獲取到鎖,就返回true,如果沒有獲取到鎖,就返回false,但是該方法會立刻返回,而不會一直等待
   boolean tryLock();
  // 這個方法和上面的tryLock差不多是一樣的,只是會嘗試指定的時間,如果在指定的時間內(nèi)拿到了鎖,則會返回true,如果在指定的時間內(nèi)沒有拿到鎖,則會返回false
   boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  // 釋放鎖
   void unlock();
  // 實現(xiàn)線程通信,相當(dāng)于wait和notify,后面會單獨講解
   Condition newCondition();
}

那么這幾個方法該如何使用了?前面我們說到,使用 Lock 是需要手動釋放鎖的,但是如果程序中拋出了異常,那么就無法做到釋放鎖,有可能引起死鎖,

所以我們在使用 Lock 的時候,有一種固定的格式,如下:

Lock l = ...;
      l.lock();
      try {
        // access the resource protected by this lock
      } finally {// 必須使用try,最后在finally里面釋放鎖
        l.unlock();
      }

下面我們來看一個簡單的例子,代碼如下:

/**
 * 描述:Lock使用
 */
public class LockDemo {
    // new一個鎖對象,注意此處必須聲明成類對象,保持只有一把鎖,ReentrantLock是Lock的唯一實現(xiàn)類
   Lock lock = new ReentrantLock();
   public void readFile(String fileMessage){
      lock.lock();// 上鎖
      try{
         System.out.println(Thread.currentThread().getName()+"得到了鎖,正在讀取文件……");
         for(int i=0; i<fileMessage.length(); i++){
            System.out.print(fileMessage.charAt(i));
         }
         System.out.println();
         System.out.println("文件讀取完畢!");
      }finally{
         System.out.println(Thread.currentThread().getName()+"釋放了鎖!");
         lock.unlock();
      }
   }
   public void demo(final String fileMessage){
      // 創(chuàng)建若干個線程
      ExecutorService service = Executors.newCachedThreadPool();
      // 提交20個任務(wù)
      for(int i=0; i<20; i++){
         service.execute(new Runnable() {
            @Override
            public void run() {
               readFile(fileMessage);
               try {
                  Thread.sleep(20);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         });
      }
    // 釋放線程池中的線程
      service.shutdown();
   }
}

Lock與synchronized的對比

1、作用

lock 和 synchronized 都是 Java 中去用來解決線程安全問題的一個工具。

2、來源

sychronized 是 Java 中的一個關(guān)鍵字。

lock 是 JUC 包里面提供的一個接口,這個接口有很多實現(xiàn)類,其中就包括我們最常用的 ReentrantLock(可重入鎖)。

3、鎖的力度

sychronized 可以通過兩種方式去控制鎖的力度:

把 sychronized 關(guān)鍵字修飾在方法層面。
修飾在代碼塊上。
鎖對象的不同:

鎖對象為靜態(tài)對象或者是class對象,那這個鎖屬于全局鎖。
鎖對象為普通實例對象,那這個鎖的范圍取決于這個實例的生命周期。
lock鎖的力度是通過 lock()與unlock()兩個方法決定的。在兩個方法之間的代碼能保證其線程安全。lock的作用域取決于lock實例的生命周期。

4、靈活性

lock鎖比sychronized的靈活性更高。

lock可以自主的去決定什么時候加鎖與釋放鎖。只需要調(diào)用lock 的lock()和unlock()這兩個方法就可以。

sychronized 由于是一個關(guān)鍵字,所以他無法實現(xiàn)非阻塞競爭鎖的方法,一個線程獲取鎖之后,其他鎖只能等待那個線程釋放之后才能有獲取鎖的機會。

5、公平鎖與非公平鎖

公平鎖:多個線程按照申請鎖的順序去獲得鎖,線程會直接進入隊列去排隊,永遠都是隊列的第一位才能得到鎖。

優(yōu)點:所有的線程都能得到資源,不會餓死。
缺點:吞吐量低,隊列里面除了第一個線程,其他的線程都會阻塞,cpu喚醒阻塞線程的開銷大。
非公平鎖:多個線程去獲取鎖的時候,會直接去嘗試獲取,獲取不到,再去進入等待隊列,如果能獲取到,就直接獲取到鎖。

優(yōu)點:可以減少CPU喚醒線程的開銷,整體的吞吐效率會高點,CPU也不必取喚醒所有線程,會減少喚起線程的數(shù)量。
缺點:可能導(dǎo)致隊列中間的線程一直獲取不到鎖或者長時間獲取不到鎖,最終餓死。
lock提供了公平鎖和非公平鎖兩種機制(默認非公平鎖)。

sychronized是非公平鎖。

6、異常是否釋放鎖

synchronized鎖的釋放是被動的,當(dāng)sychronized同步代碼塊執(zhí)行結(jié)束或者出現(xiàn)異常的時候才會被釋放。

lock鎖發(fā)生異常的時候,不會主動釋放占有的鎖,必須手動unlock()來釋放,所以我們一般都是將同步代碼塊放進try-catch里面,finally中寫入unlock()方法,避免死鎖發(fā)生。

7、判斷是否能獲取鎖

synchronized不能。

lock提供了非阻塞競爭鎖的方法trylock(),返回值是Boolean類型。它表示的是用來嘗試獲取鎖:成功獲取則返回true;獲取失敗則返回false,這個方法無論如何都會立即返回。

8、調(diào)度方式

synchronized使用的是object對象本身的wait、notify、notifyAll方法,而lock使用的是Condition進行線程之間的調(diào)度。

9、是否能中斷

synchronized只能等待鎖的釋放,不能響應(yīng)中斷。

lock等待鎖過程中可以用interrupt()來中斷。

10、性能

如果競爭不激烈,性能差不多;競爭激烈時,lock的性能會更好。

lock鎖還能使用readwritelock實現(xiàn)讀寫分離,提高多線程的讀操作效率。

11、sychronized鎖升級

synchronized 代碼塊是由一對 monitorenter/monitorexit 指令實現(xiàn)的。Monitor的實現(xiàn)完全是依靠操作系統(tǒng)內(nèi)部的互斥鎖,因為需要進行用戶態(tài)到內(nèi)核態(tài)的切換,所以同步操作是一個無差別的重量級操作。

所以現(xiàn)在JVM提供了三種不同的鎖:偏向鎖、輕量級鎖、重量級鎖。

偏向鎖:
當(dāng)沒有競爭出現(xiàn)時,默認使用偏向鎖。線程會利用 CAS 操作在對象頭上設(shè)置線程 ID ,以表示對象偏向當(dāng)前線程。

目的:在很多應(yīng)用場景中,大部分對象生命周期最多會被一個線程鎖定,使用偏向鎖可以降低無競爭時的開銷。

輕量級鎖:
JVM比較當(dāng)前線程的 threadID 和 Java 對象頭中的threadID是否一致,如果不一致(比如線程2要競爭鎖對象),那么需要查看 Java 對象頭中記錄的線程1是否存活(偏向鎖不會主動釋放因此還是存儲的線程1的 threadID),如果沒有存活,那么鎖對象還是為偏向鎖(對象頭中的threadID為線程2的);如果存活,那么撤銷偏向鎖,升級為輕量級鎖。

當(dāng)有其他線程想訪問加了輕量級鎖的資源時,會使用自旋鎖優(yōu)化,來進行資源訪問。

目的:競爭鎖對象的線程不多,而且線程持有鎖的時間也不長的情景。因為阻塞線程需要CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),開銷大,如果剛剛阻塞不久這個鎖就被釋放了,就得不償失了,因此這個時候就干脆不阻塞這個線程,讓它自旋這等待鎖釋放。

重量級鎖:
自旋失敗,很大概率 再一次自選也是失敗,因此直接升級成重量級鎖,進行線程阻塞,減少cpu消耗。

當(dāng)鎖升級為重量級鎖后,未搶到鎖的線程都會被阻塞,進入阻塞隊列。

到此這篇關(guān)于Java多線程中Lock的使用小結(jié)的文章就介紹到這了,更多相關(guān)Java多線程Lock內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IntelliJ中高效重構(gòu)的10個快捷方式詳解

    IntelliJ中高效重構(gòu)的10個快捷方式詳解

    這篇文章主要為大家介紹了IntelliJ中高效重構(gòu)的10個快捷方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Spring Cloud微服務(wù)使用webSocket的方法

    Spring Cloud微服務(wù)使用webSocket的方法

    WebSocket在現(xiàn)代瀏覽器中的應(yīng)用已經(jīng)算是比較普遍了,在某些業(yè)務(wù)場景下,要求必須能夠在服務(wù)器端推送消息至客戶端,本文給大家介紹Spring Cloud微服務(wù)使用webSocket的方法,感興趣的朋友一起看看吧
    2021-06-06
  • 詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

    詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

    這篇文章主要介紹了Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • SpringBoot中@ConditionalOnBean實現(xiàn)原理解讀

    SpringBoot中@ConditionalOnBean實現(xiàn)原理解讀

    這篇文章主要介紹了SpringBoot中@ConditionalOnBean實現(xiàn)原理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java利用iTextPDF庫實現(xiàn)制作PDF表格模板并填充數(shù)據(jù)

    Java利用iTextPDF庫實現(xiàn)制作PDF表格模板并填充數(shù)據(jù)

    這篇文章主要為大家詳細介紹了如何通過Java的iTextPDF庫制作一個PDF表格模板并填充數(shù)據(jù),文中的示例代碼講解詳細,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧
    2023-12-12
  • 三種Java自定義DNS解析器方法與實踐

    三種Java自定義DNS解析器方法與實踐

    這篇文章主要分享三種Java自定義DNS解析器方法與實踐,對于高性能的測試機(54C96G * 3)而言,可任意通過自定義Java DNS解析器來實現(xiàn)接口請求,下文內(nèi)容的實現(xiàn),需要的小伙伴可以參考一下
    2022-02-02
  • Java Spring-IOC容器與Bean管理之基于注解的方式案例詳解

    Java Spring-IOC容器與Bean管理之基于注解的方式案例詳解

    這篇文章主要介紹了Java Spring-IOC容器與Bean管理之基于注解的方式案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java線程池由淺入深掌握到精通

    Java線程池由淺入深掌握到精通

    什么是線程池?很簡單,簡單看名字就知道是裝有線程的池子,我們可以把要執(zhí)行的多線程交給線程池來處理,和連接池的概念一樣,通過維護一定數(shù)量的線程池來達到多個線程的復(fù)用
    2021-09-09
  • mybatis使用collection嵌套查詢的實現(xiàn)

    mybatis使用collection嵌套查詢的實現(xiàn)

    本文主要介紹了mybatis使用collection嵌套查詢的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • 如何擴展Spring Cache實現(xiàn)支持多級緩存

    如何擴展Spring Cache實現(xiàn)支持多級緩存

    這篇文章主要介紹了如何擴展Spring Cache實現(xiàn)支持多級緩存,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11

最新評論

宝丰县| 巴彦县| 收藏| 宜城市| 攀枝花市| 定安县| 雷州市| 宝清县| 攀枝花市| 东山县| 芦山县| 和硕县| 连云港市| 黎川县| 北川| 静宁县| 棋牌| 阿合奇县| 万全县| 大石桥市| 扎兰屯市| 青州市| 洞头县| 沂源县| 库伦旗| 鄂温| 锦屏县| 韶山市| 安国市| 武宣县| 同江市| 平远县| 平阴县| 治多县| 莲花县| 普定县| 古丈县| 旺苍县| 云南省| 青州市| 巴东县|