国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JavaEE】JUC(java.util.concurrent)的常見類以及線程安全的集合類

這篇具有很好參考價值的文章主要介紹了【JavaEE】JUC(java.util.concurrent)的常見類以及線程安全的集合類。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

1、JUC(java.util.concurrent)的常見類

1.1、Callable接口的用法(創(chuàng)建線程的一種寫法)

?1.2、ReentrantLock可重入互斥鎖

1.2.1、ReentrantLock和synchronized的區(qū)別?

1.2.2、如何選擇使用哪個鎖

1.3、Semaphore信號量

1.4、CountDownLatch

?2、線程安全的集合類

2.1、多線程環(huán)境使用ArrayList

?2.2、多線程使用隊列

2.3、多線程使用哈希表

2.3.1、HashTable和ConcurrentHashMap的區(qū)別


1、JUC(java.util.concurrent)的常見類

JUC就是取java.util.concurrent的三個單詞的首字母。所以JUC中存放的就是Java多線程開發(fā)使用到的工具類。

1.1、Callable接口的用法(創(chuàng)建線程的一種寫法)

  • Callable接口非常類似于Runnable接口,Runnable接口通過run方法描述一個任務,表示一個線程要干啥,但是run方法的返回值類型是void,不能返回一個任務的結果產出。
  • 而Callable方法是通過重寫call()方法,來描述一個線程執(zhí)行的任務,在完成結果之后,可以返回一個計算結果。

?這里我們通過一個代碼來了解Callable接口

創(chuàng)建線程計算1+2+3+.....+1000,使用Callable版本

  • 創(chuàng)建一個匿名內部類,實現Callable接口,Callable帶有泛型參數,泛型參數表示返回值的類型
  • 重寫Callable的call方法,完成累加的過程,直接通過返回值返回計算結果。
  • 把callable實例使用FutuerTask包裝一下
  • 創(chuàng)建線程,線程的構造方法傳入FutureTask,此時新線程就會執(zhí)行FutureTask內部的Callable的call方法,完成計算,計算結果就放到FutureTask對象中。
  • 在主線程中調用futureTask.get()能夠阻塞等待新線程計算完畢,并獲取到FutureTask中的結果。
public class TestDemo27 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //創(chuàng)建一個任務
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i < 1000; i++) {
                    sum += i;
                }
                return sum;
            }
        };

        //創(chuàng)建一個線程,來執(zhí)行第一個任務
        //Thread構造方法 不能直接將callable對象作為參數,需要使用FutureTask類進行包裝一下,將FutureTask對象作為參數傳給Thread。
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();
        System.out.println(futureTask.get());
    }
}

?我們這里來理解一下FutureTask類的作用。

我們去餐館吃飯,在我們將菜點了之后,服務員給后廚大廚一張小票,也給我們一張小票。讓后廚大廚根據小票上的要求制作,讓我們通過小票去領我們自己的飯。我們使用的FutureTask就相當于一個小票,我們此時將futureTask傳給t線程,就相當于大廚通過小票知道他要怎樣做。我們通過futureTask.get()獲取計算出來的結果,也就是我們的飯。


???在上述的代碼中,執(zhí)行任務在t線程,而獲取任務執(zhí)行結果在主線程,這怎么能夠確定多線程執(zhí)行時,t線程一定在主線程之前結束??

???我們在主線程中futureTask調用get方法,這個get方法,就有相當于join的作用,他會阻塞等待t線程執(zhí)行完畢,再去執(zhí)行主線程中的get方法。

?總結Callable

  • Callable和Runnable相對,都是描述一個"任務"。Callable描述的是帶有返回值的任務,Runnable描述的是不帶返回值的任務。
  • Callable通常需要搭配FutureTask來使用。FutureTask用來保存Callable的返回值結果,因為Callable往往是在另一個線程中執(zhí)行的,啥時候執(zhí)行完并不確定。
  • FutureTask就可以負責這個等待結果出來的工作。

?1.2、ReentrantLock可重入互斥鎖

ReentranLock這是鎖的另一種實現方式,和synchronized定位類似,都是用來實現互斥效果,保證線程安全。

?ReentrantLock的用法:

  • lock():加鎖,如果獲取不到鎖就死等。
  • trylock(超時時間):加鎖,如果獲取不到鎖,等待一定的時間之后就會放棄加鎖。
  • unlock():解鎖

1.2.1、ReentrantLock和synchronized的區(qū)別?

  1. synchronized是一個關鍵字,是JVM內部實現的(大概率是基于C++實現),ReentranLock是標準庫中的一個類,在JVM外實現的(基于Java實現)
  2. synchronized使用時不需要手動釋放鎖ReentrantLock使用時需要手動釋放,使用起來更靈活,但是也容易遺漏unlock
  3. synchronized申請鎖的失敗時,會死等。ReentrantLock可以通過trylock的方式等待一段時間就放棄。(讓程序員更靈活的決定接下來咋做)
  4. synchronized是非公平鎖,ReentrantLock默認是非公平鎖,但是它提供了公平和非公平兩種工作模式,可以通過構造方法傳入一個true開啟公平鎖模式。
  5. 更強大的喚醒機制,synchronized是通過Object的wait/notify實現等待-喚醒,每次喚醒的是一個隨機等待的線程,ReentrantLock搭配Condition類實現等待-喚醒。Condition這個類也能起到等待通知的效果,可以更精確控制喚醒某個指定的線程。

1.2.2、如何選擇使用哪個鎖

  • 鎖競爭不激烈的時候,使用synchronized,效率更高,自動釋放更方便。
  • 鎖競爭激烈的時候,使用ReentrantLock,搭配trylock更靈活的控制加鎖的行為,而不是死等。
  • 如果需要使用公平鎖,使用ReentrantLock.

1.3、Semaphore信號量

信號量:用來表示"可用資源的個數"。本質上就是一個計數器。

?理解信號量

  • 可以把信號量想象成是停車場的展示牌:當前有車位100個,表示有100個可用資源。
  • 當有車開進去的時候,就相當于申請一個可用資源,可用車位就-1(這個稱為信號量的P操作)
  • 當有車開出來的時候,就相當于釋放一個可用資源,可用車位就+1(這個稱為信號量的V操作)
  • 如果計數器的值已經為0了,還嘗試申請資源,就會阻塞等待,直到其他線程釋放資源。

Semaphore的PV操作中的加減計數器操作都是原子的,可以在多線程環(huán)境下直接使用。

  1. 我們所說的鎖,本質上是計數器為1的信號量,可用資源只有做一個,取值只有1和0兩種,也叫做二元信號量。?一個線程獲取到鎖,這個時候信號量為0,只有等到線程將該鎖釋放掉,這個時候信號量為1,其他線程才能獲取到鎖。
  2. 我們可以認為信號量是更廣義的鎖,他不僅能管理鎖,這中非0即1的資源;也能管理多個資源。

1.4、CountDownLatch

  • 同時等待N個任務執(zhí)行結束。
  • 就好比跑步比賽,6個選手依次就位,發(fā)令槍一響,就表示開始,當最后一個人沖過終點,才能公布成績。

?將上面的情況可以使用多線程的思路進行描述

  1. 主線程,創(chuàng)建10個線程。主線程創(chuàng)建一個CountDownLatch對象,構造方法參數寫10(表示10個參賽選手),10個線程分別完成各自的任務。
  2. 主線程使用CountDownLatch.await方法,來阻塞等待所有線程都執(zhí)行完任務。
  3. 10個線程每個線程執(zhí)行完都會調用一個CountDownLatch.countDown方法表示選手到達終點)
  4. 10個線程在調用countDown方法時,主線程調用的await方法會記錄有幾個線程調用了countDown方法(就相當于,裁判員在記錄有幾個選手已經過線了),當這10個線程都調用過countDown方法之后,此時主線程的await就會阻塞接觸,接下來就可以進行后續(xù)工作了。

?2、線程安全的集合類

我們在數據結構中說到的ArrayList、LinkedList、HashMap、PriorityQueue都是線程不安全的集合類。在多線程環(huán)境下使用,有可能會出現問題。

?這些數據結構多線程不安全,但是還要使用,該做怎樣的處理呢?

2.1、多線程環(huán)境使用ArrayList

1??最直接的方法,就是使用鎖(synchronized或ReentrantLock),手動保證.

多個線程去修改ArrayList此時就可能有問題,就可以給修改操作進行加鎖。

2??、可以使用Vector類來代替ArrayList類。

Vector類中的關鍵方法都是帶有synchronized的,這樣可以保證在多線程環(huán)境下,這個類是安全的。但是Java官方明確表示,將Vector這個類標記為不建議使用的類。

3??、?使用collections.synchronizedList(new list集合類)

  • collections.synchronizedList它就相當于一個外殼,將我們想要使用的list集合類,放在它里面,讓list集合類當中的關鍵操作都帶上synchronized。
  • synchronizedList是標準庫提供的一個基于synchronized進行線程同步的List.
  • synchronizedList的關鍵操作上都帶有synchronized

4??、 使用CopyOnWriteArrayList(支持"寫時拷貝"的集合類)

CopyOnWrite容器即寫時復制的容器。

  • 當我們往一個容器里添加元素的時候,不直接往當前容器中添加,而是先將當前容器進行Copy,復制出一個新的容器,然后往新的容器里添加元素。
  • 添加完元素之后,在將原容器的引用指向新的容器。(引用的賦值操作,本身就是原子的)

所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫是不同的容器。

多線程讀ArrayList是,此時沒有線程安全的問題,但是當一些線程讀,一些線程修改的時候,就會出現線程安全問題,但是使用CopyOnWriteArrayList,就不會產生線程安全問題了,讀和寫相互不影響。


  • 優(yōu)點:這樣做的好處就是,修改的同時對于讀操作,是沒有任何影響的,讀的時候就會讀取原來的舊數據,不會出現,讀一個帶有"修改了一半"的中間版本,也就是說適合于讀多寫少的情況,也適合數據小的情況,在我們日常配置數據的時候,經常就會用到這類操作。這種策略也叫做"雙緩沖區(qū)策略"。就像我們在打游戲的時候,顯卡就是采用的這種方式,顯示器在讀前一幀的畫面的時候,顯卡在畫下一幀的畫面。讀的時候,在舊的集合中讀,寫的時候在新的集合中寫,兩種不會產生影響。
  • 缺點:占用內存較多,新寫的數據不能第一時間讀取到。

?2.2、多線程使用隊列

我們之前說過的BlockingQueue就是線程安全的,在之前線程池的博客中已經說到了,這里就不過多說明了。

2.3、多線程使用哈希表

HashMap本身不是線程安全的。

??在多線程環(huán)境下使用哈希表可以使用:

1??HashTable(雖然線程安全,但是不建議使用)

HashTable只是簡單的把關鍵方法加上了synchronized關鍵字。

2??ConcurrentHashMap(建議使用)

2.3.1、HashTable和ConcurrentHashMap的區(qū)別

1??加鎖粒度的不同(觸發(fā)鎖沖突的頻率)

HashTable是針對整個哈希表加鎖,任何的增刪改查操作,都會觸發(fā)加鎖,也就都會可能有鎖競爭。

??我們通過下面的場景來展現HashTable出現的問題

【JavaEE】JUC(java.util.concurrent)的常見類以及線程安全的集合類

??此時我們通過下面的場景來展現ConcurrentHashMap在遇到與HashTable相同的問題時,它的處理方式,以及優(yōu)點。

【JavaEE】JUC(java.util.concurrent)的常見類以及線程安全的集合類

?

???補充:

上述情況是從Java1.8開始的,在Java1.7及其之前,ConcurrentHashMap使用"分段鎖",目的和上述類似,相當于是好幾個鏈表共用一把鎖(這個設定,不科學,效率不夠高,代碼寫起來也比較麻煩)

2??ConcurrentHashMap更充分的利用了CAS機制(無鎖編程),比如獲取或更新元素個數,就可以直接使用CAS完成,不必加鎖。

3??優(yōu)化了擴容策略

??對于HashTable,如果元素太多,就會涉及到擴容,擴容需要重新申請內存空間,搬運元素(把元素從舊的哈希表上刪除,插入到新的哈希表上)。如果舊的HashTable中的元素非常多,搬運一次,成本就很高。剛好給HashTable中插入(put)元素的時候,負載因子超過了閾值,一次性搬運全部數據就會導致put操作非常的卡頓。

??對于ConcurrentHashMap擴容的策略,是化整為零,它不會試圖依次性的把所有的元素都搬運到新表當中去,而是每次搬運一部分。文章來源地址http://www.zghlxwxcb.cn/news/detail-469319.html

  • 當put觸發(fā)擴容,此時就會直接創(chuàng)建更大的內存空間,但是并不會直接把所有元素都搬運過去,而是值搬運一小部分,這個時候的搬運速度就會比較快。
  • 此時就相當于存在兩份hash表了,此時插入元素操作,就會直接往新表中插入元素;刪除元素,就會刪除舊表當中的元素;查找元素,就會新表和舊表一起都查。并且每次操作過程中,都搬運一部分元素,直至最后搬運完成。

到了這里,關于【JavaEE】JUC(java.util.concurrent)的常見類以及線程安全的集合類的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • javaEE初階——多線程(九)——JUC常見的類以及線程安全的集合類

    javaEE初階——多線程(九)——JUC常見的類以及線程安全的集合類

    T04BF ??專欄: 算法|JAVA|MySQL|C語言 ?? 小比特 大夢想 此篇文章與大家分享多線程專題的最后一篇文章:關于JUC常見的類以及線程安全的集合類 如果有不足的或者錯誤的請您指出! 3.1Callable接口 Callable和Runnable一樣,都是用來描述一個任務的 但是區(qū)別在于 ,用Callable描述的任務是有

    2024年04月25日
    瀏覽(22)
  • JUC并發(fā)編程-集合不安全情況以及Callable線程創(chuàng)建方式

    JUC并發(fā)編程-集合不安全情況以及Callable線程創(chuàng)建方式

    1)List 不安全 ArrayList 在并發(fā)情況下是不安全的 解決方案 : 1.Vector 2.Collections.synchonizedList() 3. CopyOnWriteArrayList 核心思想 是,如果有 多個調用者(Callers)同時要求相同的資源 (如內存或者是磁盤上的數據存儲),他們 會共同獲取相同的指針指向相同的資源 , 直到某個調用者

    2024年01月23日
    瀏覽(39)
  • 如何解決java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7566d7cf r...

    Java中的 java.util.concurrent.RejectedExecutionException 異常表示無法將任務提交到線程池中執(zhí)行。這通常是因為線程池處于關閉狀態(tài)或者已經達到了最大線程數,無法再接受新的任務。 要解決這個異常,你可以考慮以下幾種方法: 檢查線程池的狀態(tài),確保它處于可以接受新任務的狀態(tài)

    2024年02月13日
    瀏覽(36)
  • java.util.concurrent.Executionexception 異常

    java.util.concurrent.Executionexception 異常

    今天運行時發(fā)生了如下報錯。自己搗鼓半天也沒發(fā)現問題出在哪兒,感謝大佬的幫助,記錄下來防止再犯。。 caused by org.apache.flink.client.program.programInvocationException: Job failed。程序調用異常。網上找了很多解決方法,都沒有能夠解決這個問題。 直到在報錯中發(fā)現了這一行: C

    2024年02月19日
    瀏覽(43)
  • 已解決java.util.concurrent.ExecutionException異常的正確解決方法,親測有效?。?!

    已解決java.util.concurrent.ExecutionException異常的正確解決方法,親測有效?。?! java.util.concurrent.ExecutionException java.util.concurrent.ExecutionException是Java多線程編程中常見的異常之一,它表示在執(zhí)行一個Callable或者Runnable任務時,任務拋出了一個異常。 下滑查看解決方法 具體解決方法可

    2024年02月11日
    瀏覽(24)
  • flink1.15 savepoint 超時報錯 java.util.concurrent.TimeoutException
  • 關于報錯java.lang.reflect.InaccessibleObjectException: Unable to make field private java.util.concurrent

    java.lang.reflect.InaccessibleObjectException: Unable to make field private java.util.concurrent.Callable java.util.concurrent.FutureTask.callable accessible: module java.base does not \\\"opens java.util.concurrent\\\" to unnamed module @32eebfca 假如報這種錯誤,只需要在Run-Edit Configurations-Modify Options-add VM options中加? 假如你報的是下面

    2024年02月15日
    瀏覽(95)
  • 【問題已解決】Unrecognized option: --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED

    【問題已解決】Unrecognized option: --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED

    今天在創(chuàng)建java項目時,運行報錯,說無法成功創(chuàng)建java程序。 Unrecognized option: --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. 解決辦法: 1、使用最新的jdk版本 2、在第三處,選擇最新的jdk版本

    2024年02月13日
    瀏覽(33)
  • 【Java多線程】線程中幾個常見的屬性以及狀態(tài)

    【Java多線程】線程中幾個常見的屬性以及狀態(tài)

    目錄 Thread的幾個常見屬性 1、Id 2、Name名稱 3、State狀態(tài) 4、Priority優(yōu)先級 5、Daemon后臺線程 6、Alive存活 ? ID 是線程的唯一標識,由系統(tǒng)自動分配,不同線程不會重復。 用戶定義的名稱。該名稱在各種調試工具中都會用到。 狀態(tài)表示線程當前所處的一個情況。和進程一樣,線程

    2024年02月19日
    瀏覽(17)
  • JUC面試(五)——Collection線程不安全

    JUC面試(五)——Collection線程不安全

    當我們執(zhí)行下面語句的時候,底層進行了什么操作 new ArrayListInteger(); 底層創(chuàng)建了一個空的數組,伴隨著初始值為10 當執(zhí)行add方法后,如果超過了10,那么會進行擴容,擴容的大小為原值的一半,也就是5個,使用下列方法擴容 Arrays.copyOf(elementData, netCapacity) 單線程環(huán)境 單線程環(huán)

    2023年04月23日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包