1. Java 多線程,八股文!

        共 9111字,需瀏覽 19分鐘

         ·

        2021-08-29 23:44

        直接進入正題,發(fā)車!

        簡述java內(nèi)存模型(JMM)

        java內(nèi)存模型定義了程序中各種變量的訪問規(guī)則。其規(guī)定所有變量都存儲在主內(nèi)存,線程均有自己的工作內(nèi)存。工作內(nèi)存中保存被該線程使用的變量的主內(nèi)存副本,線程對變量的所有操作都必須在工作空間進行,不能直接讀寫主內(nèi)存數(shù)據(jù)。操作完成后,線程的工作內(nèi)存通過緩存一致性協(xié)議將操作完的數(shù)據(jù)刷回主存。

        簡述as-if-serial

        編譯器等會對原始的程序進行指令重排序和優(yōu)化。但不管怎么重排序,其結(jié)果和用戶原始程序輸出預(yù)定結(jié)果一致。

        簡述happens-before八大原則

        程序次序規(guī)則:一個線程內(nèi)寫在前面的操作先行發(fā)生于后面的。

        鎖定規(guī)則:unlock 操作先行發(fā)生于后面對同一個鎖的 lock 操作。

        volatile 規(guī)則:對 volatile 變量的寫操作先行發(fā)生于后面的讀操作。

        線程啟動規(guī)則:線程的 start 方法先行發(fā)生于線程的每個動作。

        線程中斷規(guī)則:對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生。

        線程終止規(guī)則:線程中所有操作先行發(fā)生于對線程的終止檢測。

        對象終結(jié)規(guī)則:對象的初始化先行發(fā)生于 finalize 方法。

        傳遞性規(guī)則:如果操作 A 先行發(fā)生于操作 B,操作 B 先行發(fā)生于操作 C,那么操作 A 先行發(fā)生于操作 C

        as-if-serial 和 happens-before 的區(qū)別

        as-if-serial 保證單線程程序的執(zhí)行結(jié)果不變,happens-before 保證正確同步的多線程程序的執(zhí)行結(jié)果不變。

        簡述原子性操作

        一個操作或者多個操作,要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷,要么就都不執(zhí)行,這就是原子性操作。

        簡述線程的可見性

        可見性指當(dāng)一個線程修改了共享變量時,其他線程能夠立即得知修改。volatile,synchronized,final都能保證可見性。

        簡述有序性

        即雖然多線程存在并發(fā)和指令優(yōu)化等操作,在本線程內(nèi)觀察該線程的所有執(zhí)行操作是有序的。

        簡述java中volatile關(guān)鍵字作用

        1. 保證變量對所有線程的可見性。當(dāng)一條線程修改了變量值,新值對于其他線程來說是立即可以得知的。
        2. 禁止指令重排序優(yōu)化。使用 volatile 變量進行寫操作,匯編指令帶有 lock 前綴,相當(dāng)于一個內(nèi)存屏障,編譯器不會將后面的指令重排到內(nèi)存屏障之前。

        java線程的實現(xiàn)方式

        1. 實現(xiàn)Runnable接口
        2. 繼承Thread類。
        3. 實現(xiàn)Callable接口

        簡述java線程的狀態(tài)

        線程狀態(tài)有New, RUNNABLE, BLOCK, WAITING, TIMED_WAITING, THERMINATED NEW:新建狀態(tài),線程被創(chuàng)建且未啟動,此時還未調(diào)用 start 方法。

        RUNNABLE: 運行狀態(tài)。其表示線程正在JVM中執(zhí)行,但是這個執(zhí)行,不一定真的在跑,也可能在排隊等CPU。

        BLOCKED:阻塞狀態(tài)。線程等待獲取鎖,鎖還沒獲得。

        WAITING: 等待狀態(tài)。線程內(nèi)run方法運行完語句Object.wait()/Thread.join()進入該狀態(tài)。

        TIMED_WAITING:限期等待。在一定時間之后跳出狀態(tài)。調(diào)用Thread.sleep(long) Object.wait(long) Thread.join(long)進入狀態(tài)。其中這些參數(shù)代表等待的時間。

        TERMINATED:結(jié)束狀態(tài)。線程調(diào)用完run方法進入該狀態(tài)。

        簡述線程通信的方式

        1. volatile 關(guān)鍵詞修飾變量,保證所有線程對變量訪問的可見性。
        2. synchronized關(guān)鍵詞。確保多個線程在同一時刻只能有一個處于方法或同步塊中。
        3. wait/notify方法
        4. IO通信

        簡述線程池

        沒有線程池的情況下,多次創(chuàng)建,銷毀線程開銷比較大。如果在開辟的線程執(zhí)行完當(dāng)前任務(wù)后執(zhí)行接下來任務(wù),復(fù)用已創(chuàng)建的線程,降低開銷、控制最大并發(fā)數(shù)。

        線程池創(chuàng)建線程時,會將線程封裝成工作線程 Worker,Worker 在執(zhí)行完任務(wù)后還會循環(huán)獲取工作隊列中的任務(wù)來執(zhí)行。

        將任務(wù)派發(fā)給線程池時,會出現(xiàn)以下幾種情況

        1. 核心線程池未滿,創(chuàng)建一個新的線程執(zhí)行任務(wù)。

        2. 如果核心線程池已滿,工作隊列未滿,將線程存儲在工作隊列。

        3. 如果工作隊列已滿,線程數(shù)小于最大線程數(shù)就創(chuàng)建一個新線程處理任務(wù)。

        4. 如果超過大小線程數(shù),按照拒絕策略來處理任務(wù)。

        線程池參數(shù)

        1. corePoolSize:常駐核心線程數(shù)。超過該值后如果線程空閑會被銷毀。

        2. maximumPoolSize:線程池能夠容納同時執(zhí)行的線程最大數(shù)。

        3. keepAliveTime:線程空閑時間,線程空閑時間達到該值后會被銷毀,直到只剩下 corePoolSize 個線程為止,避免浪費內(nèi)存資源。

        4. workQueue:工作隊列。

        5. threadFactory:線程工廠,用來生產(chǎn)一組相同任務(wù)的線程。

        6. handler:拒絕策略。有以下幾種拒絕策略:

        • AbortPolicy:丟棄任務(wù)并拋出異常
        • CallerRunsPolicy:重新嘗試提交該任務(wù)
        • DiscardOldestPolicy 拋棄隊列里等待最久的任務(wù)并把當(dāng)前任務(wù)加入隊列
        • DiscardPolicy 表示直接拋棄當(dāng)前任務(wù)但不拋出異常。

        線程池創(chuàng)建方法

        1. newFixedThreadPool,創(chuàng)建固定大小的線程池。

        2. newSingleThreadExecutor,使用單線程線程池。

        3. newCachedThreadPool,maximumPoolSize 設(shè)置為 Integer 最大值,工作完成后會回收工作線程

        4. newScheduledThreadPool:支持定期及周期性任務(wù)執(zhí)行,不回收工作線程。

        5. newWorkStealingPool:一個擁有多個任務(wù)隊列的線程池。

        簡述Executor框架

        Executor框架目的是將任務(wù)提交和任務(wù)如何運行分離開來的機制。用戶不再需要從代碼層考慮設(shè)計任務(wù)的提交運行,只需要調(diào)用Executor框架實現(xiàn)類的Execute方法就可以提交任務(wù)。產(chǎn)生線程池的函數(shù)ThreadPoolExecutor也是Executor的具體實現(xiàn)類。

        簡述Executor的繼承關(guān)系

        • Executor:一個接口,其定義了一個接收Runnable對象的方法executor,該方法接收一個Runable實例執(zhí)行這個任務(wù)。
        • ExecutorService:Executor的子類接口,其定義了一個接收Callable對象的方法,返回 Future 對象,同時提供execute方法。
        • ScheduledExecutorService:ExecutorService的子類接口,支持定期執(zhí)行任務(wù)。
        • AbstractExecutorService:抽象類,提供 ExecutorService 執(zhí)行方法的默認實現(xiàn)。
        • Executors:實現(xiàn)ExecutorService接口的靜態(tài)工廠類,提供了一系列工廠方法用于創(chuàng)建線程池。
        • ThreadPoolExecutor:繼承AbstractExecutorService,用于創(chuàng)建線程池。
        • ForkJoinPool: 繼承AbstractExecutorService,F(xiàn)ork 將大任務(wù)分叉為多個小任務(wù),然后讓小任務(wù)執(zhí)行,Join 是獲得小任務(wù)的結(jié)果,類似于map reduce。
        • ThreadPoolExecutor:繼承ThreadPoolExecutor,實現(xiàn)ScheduledExecutorService,用于創(chuàng)建帶定時任務(wù)的線程池。

        簡述線程池的狀態(tài)

        • Running:能接受新提交的任務(wù),也可以處理阻塞隊列的任務(wù)。
        • Shutdown:不再接受新提交的任務(wù),但可以處理存量任務(wù),線程池處于running時調(diào)用shutdown方法,會進入該狀態(tài)。
        • Stop:不接受新任務(wù),不處理存量任務(wù),調(diào)用shutdownnow進入該狀態(tài)。
        • Tidying:所有任務(wù)已經(jīng)終止了,worker_count(有效線程數(shù))為0。
        • Terminated:線程池徹底終止。在tidying模式下調(diào)用terminated方法會進入該狀態(tài)。

        簡述阻塞隊列

        阻塞隊列是生產(chǎn)者消費者的實現(xiàn)具體組件之一。當(dāng)阻塞隊列為空時,從隊列中獲取元素的操作將會被阻塞,當(dāng)阻塞隊列滿了,往隊列添加元素的操作將會被阻塞。具體實現(xiàn)有:

        • ArrayBlockingQueue:底層是由數(shù)組組成的有界阻塞隊列。
        • LinkedBlockingQueue:底層是由鏈表組成的有界阻塞隊列。
        • PriorityBlockingQueue:阻塞優(yōu)先隊列。
        • DelayQueue:創(chuàng)建元素時可以指定多久才能從隊列中獲取當(dāng)前元素
        • SynchronousQueue:不存儲元素的阻塞隊列,每一個存儲必須等待一個取出操作
        • LinkedTransferQueue:與LinkedBlockingQueue相比多一個transfer方法,即如果當(dāng)前有消費者正等待接收元素,可以把生產(chǎn)者傳入的元素立刻傳輸給消費者。
        • LinkedBlockingDeque:雙向阻塞隊列。

        談一談ThreadLocal

        ThreadLocal 是線程共享變量。ThreadLoacl 有一個靜態(tài)內(nèi)部類 ThreadLocalMap,其 Key 是 ThreadLocal 對象,值是 Entry 對象,ThreadLocalMap是每個線程私有的。

        • set 給ThreadLocalMap設(shè)置值。
        • get 獲取ThreadLocalMap。
        • remove 刪除ThreadLocalMap類型的對象。

        存在的問題

        1. 對于線程池,由于線程池會重用 Thread 對象,因此與 Thread 綁定的 ThreadLocal 也會被重用,造成一系列問題。

        2. 內(nèi)存泄漏。由于 ThreadLocal 是弱引用,但 Entry 的 value 是強引用,因此當(dāng) ThreadLocal 被垃圾回收后,value 依舊不會被釋放,產(chǎn)生內(nèi)存泄漏。

        聊聊你對java并發(fā)包下unsafe類的理解

        對于 Java 語言,沒有直接的指針組件,一般也不能使用偏移量對某塊內(nèi)存進行操作。這些操作相對來講是安全(safe)的。

        Java 有個類叫 Unsafe 類,這個類類使 Java 擁有了像 C 語言的指針一樣操作內(nèi)存空間的能力,同時也帶來了指針的問題。這個類可以說是 Java 并發(fā)開發(fā)的基礎(chǔ)。

        JAVA中的樂觀鎖與CAS算法

        對于樂觀鎖,開發(fā)者認為數(shù)據(jù)發(fā)送時發(fā)生并發(fā)沖突的概率不大,所以讀操作前不上鎖。

        到了寫操作時才會進行判斷,數(shù)據(jù)在此期間是否被其他線程修改。如果發(fā)生修改,那就返回寫入失??;如果沒有被修改,那就執(zhí)行修改操作,返回修改成功。

        樂觀鎖一般都采用 Compare And Swap(CAS)算法進行實現(xiàn)。顧名思義,該算法涉及到了兩個操作,比較(Compare)和交換(Swap)。

        CAS 算法的思路如下:

        1. 該算法認為不同線程對變量的操作時產(chǎn)生競爭的情況比較少。
        2. 該算法的核心是對當(dāng)前讀取變量值 E 和內(nèi)存中的變量舊值 V 進行比較。
        3. 如果相等,就代表其他線程沒有對該變量進行修改,就將變量值更新為新值 N。
        4. 如果不等,就認為在讀取值 E 到比較階段,有其他線程對變量進行過修改,不進行任何操作。

        ABA問題及解決方法簡述

        CAS 算法是基于值來做比較的,如果當(dāng)前有兩個線程,一個線程將變量值從 A 改為 B ,再由 B 改回為 A ,當(dāng)前線程開始執(zhí)行 CAS 算法時,就很容易認為值沒有變化,誤認為讀取數(shù)據(jù)到執(zhí)行 CAS 算法的期間,沒有線程修改過數(shù)據(jù)。

        juc 包提供了一個 AtomicStampedReference,即在原始的版本下加入版本號戳,解決 ABA 問題。

        簡述常見的Atomic類

        在很多時候,我們需要的僅僅是一個簡單的、高效的、線程安全的++或者--方案,使用synchronized關(guān)鍵字和lock固然可以實現(xiàn),但代價比較大,此時用原子類更加方便?;緮?shù)據(jù)類型的原子類有:

        • AtomicInteger 原子更新整形
        • AtomicLong 原子更新長整型
        • AtomicBoolean 原子更新布爾類型

        Atomic數(shù)組類型有:

        • AtomicIntegerArray 原子更新整形數(shù)組里的元素
        • AtomicLongArray 原子更新長整型數(shù)組里的元素
        • AtomicReferenceArray 原子更新引用類型數(shù)組里的元素。

        Atomic引用類型有

        • AtomicReference 原子更新引用類型
        • AtomicMarkableReference 原子更新帶有標(biāo)記位的引用類型,可以綁定一個 boolean 標(biāo)記
        • AtomicStampedReference 原子更新帶有版本號的引用類型

        FieldUpdater類型:

        • AtomicIntegerFieldUpdater 原子更新整形字段的更新器
        • AtomicLongFieldUpdater 原子更新長整形字段的更新器
        • AtomicReferenceFieldUpdater 原子更新引用類型字段的更新器

        簡述Atomic類基本實現(xiàn)原理

        以AtomicIntger 為例:方法getAndIncrement:以原子方式將當(dāng)前的值加1,具體實現(xiàn)為:

        1. 在 for 死循環(huán)中取得 AtomicInteger 里存儲的數(shù)值
        2. 對 AtomicInteger 當(dāng)前的值加 1
        3. 調(diào)用 compareAndSet 方法進行原子更新
        4. 先檢查當(dāng)前數(shù)值是否等于 expect
        5. 如果等于則說明當(dāng)前值沒有被其他線程修改,則將值更新為 next,
        6. 如果不是會更新失敗返回 false,程序會進入 for 循環(huán)重新進行 compareAndSet 操作。

        簡述CountDownLatch

        countDownLatch這個類使一個線程等待其他線程各自執(zhí)行完畢后再執(zhí)行。是通過一個計數(shù)器來實現(xiàn)的,計數(shù)器的初始值是線程的數(shù)量。每當(dāng)一個線程執(zhí)行完畢后,調(diào)用countDown方法,計數(shù)器的值就減1,當(dāng)計數(shù)器的值為0時,表示所有線程都執(zhí)行完畢,然后在等待的線程就可以恢復(fù)工作了。只能一次性使用,不能reset。

        簡述CyclicBarrier

        CyclicBarrier 主要功能和countDownLatch類似,也是通過一個計數(shù)器,使一個線程等待其他線程各自執(zhí)行完畢后再執(zhí)行。但是其可以重復(fù)使用(reset)。

        簡述Semaphore

        Semaphore即信號量。Semaphore 的構(gòu)造方法參數(shù)接收一個 int 值,設(shè)置一個計數(shù)器,表示可用的許可數(shù)量即最大并發(fā)數(shù)。使用 acquire 方法獲得一個許可證,計數(shù)器減一,使用 release 方法歸還許可,計數(shù)器加一。如果此時計數(shù)器值為0,線程進入休眠。

        簡述Exchanger

        Exchanger類可用于兩個線程之間交換信息??珊唵蔚貙xchanger對象理解為一個包含兩個格子的容器,通過exchanger方法可以向兩個格子中填充信息。線程通過exchange 方法交換數(shù)據(jù),第一個線程執(zhí)行 exchange 方法后會阻塞等待第二個線程執(zhí)行該方法。當(dāng)兩個線程都到達同步點時這兩個線程就可以交換數(shù)據(jù)當(dāng)兩個格子中的均被填充時,該對象會自動將兩個格子的信息交換,然后返回給線程,從而實現(xiàn)兩個線程的信息交換。

        簡述ConcurrentHashMap

        JDK7采用鎖分段技術(shù)。首先將數(shù)據(jù)分成 Segment 數(shù)據(jù)段,然后給每一個數(shù)據(jù)段配一把鎖,當(dāng)一個線程占用鎖訪問其中一個段的數(shù)據(jù)時,其他段的數(shù)據(jù)也能被其他線程訪問。

        get 除讀到空值不需要加鎖。該方法先經(jīng)過一次再散列,再用這個散列值通過散列運算定位到 Segment,最后通過散列算法定位到元素。put 須加鎖,首先定位到 Segment,然后進行插入操作,第一步判斷是否需要對 Segment 里的 HashEntry 數(shù)組進行擴容,第二步定位添加元素的位置,然后將其放入數(shù)組。

        JDK8的改進

        1. 取消分段鎖機制,采用CAS算法進行值的設(shè)置,如果CAS失敗再使用 synchronized 加鎖添加元素
        2. 引入紅黑樹結(jié)構(gòu),當(dāng)某個槽內(nèi)的元素個數(shù)超過8且 Node數(shù)組 容量大于 64 時,鏈表轉(zhuǎn)為紅黑樹。
        3. 使用了更加優(yōu)化的方式統(tǒng)計集合內(nèi)的元素數(shù)量。

        Synchronized底層實現(xiàn)原理

        Java 對象底層都關(guān)聯(lián)一個的 monitor,使用 synchronized 時 JVM 會根據(jù)使用環(huán)境找到對象的 monitor,根據(jù) monitor 的狀態(tài)進行加解鎖的判斷。如果成功加鎖就成為該 monitor 的唯一持有者,monitor 在被釋放前不能再被其他線程獲取。

        synchronized在JVM編譯后會產(chǎn)生monitorenter 和 monitorexit 這兩個字節(jié)碼指令,獲取和釋放 monitor。這兩個字節(jié)碼指令都需要一個引用類型的參數(shù)指明要鎖定和解鎖的對象,對于同步普通方法,鎖是當(dāng)前實例對象;對于靜態(tài)同步方法,鎖是當(dāng)前類的 Class 對象;對于同步方法塊,鎖是 synchronized 括號里的對象。

        執(zhí)行 monitorenter 指令時,首先嘗試獲取對象鎖。如果這個對象沒有被鎖定,或當(dāng)前線程已經(jīng)持有鎖,就把鎖的計數(shù)器加 1,執(zhí)行 monitorexit 指令時會將鎖計數(shù)器減 1。一旦計數(shù)器為 0 鎖隨即就被釋放。

        Synchronized關(guān)鍵詞使用方法

        1. 直接修飾某個實例方法
        2. 直接修飾某個靜態(tài)方法
        3. 修飾代碼塊

        簡述java偏向鎖

        JDK 1.6 中提出了偏向鎖的概念。該鎖提出的原因是,開發(fā)者發(fā)現(xiàn)多數(shù)情況下鎖并不存在競爭,一把鎖往往是由同一個線程獲得的。偏向鎖并不會主動釋放,這樣每次偏向鎖進入的時候都會判斷該資源是否是偏向自己的,如果是偏向自己的則不需要進行額外的操作,直接可以進入同步操作。

        其申請流程為:

        1. 首先需要判斷對象的 Mark Word 是否屬于偏向模式,如果不屬于,那就進入輕量級鎖判斷邏輯。否則繼續(xù)下一步判斷;
        2. 判斷目前請求鎖的線程 ID 是否和偏向鎖本身記錄的線程 ID 一致。如果一致,繼續(xù)下一步的判斷,如果不一致,跳轉(zhuǎn)到步驟4;
        3. 判斷是否需要重偏向。如果不用的話,直接獲得偏向鎖;
        4. 利用 CAS 算法將對象的 Mark Word 進行更改,使線程 ID 部分換成本線程 ID。如果更換成功,則重偏向完成,獲得偏向鎖。如果失敗,則說明有多線程競爭,升級為輕量級鎖。

        簡述輕量級鎖

        輕量級鎖是為了在沒有競爭的前提下減少重量級鎖出現(xiàn)并導(dǎo)致的性能消耗。

        其申請流程為:

        1. 如果同步對象沒有被鎖定,虛擬機將在當(dāng)前線程的棧幀中建立一個鎖記錄空間,存儲鎖對象目前 Mark Word 的拷貝。
        2. 虛擬機使用 CAS 嘗試把對象的 Mark Word 更新為指向鎖記錄的指針
        3. 如果更新成功即代表該線程擁有了鎖,鎖標(biāo)志位將轉(zhuǎn)變?yōu)?00,表示處于輕量級鎖定狀態(tài)。
        4. 如果更新失敗就意味著至少存在一條線程與當(dāng)前線程競爭。虛擬機檢查對象的 Mark Word 是否指向當(dāng)前線程的棧幀
        5. 如果指向當(dāng)前線程的棧幀,說明當(dāng)前線程已經(jīng)擁有了鎖,直接進入同步塊繼續(xù)執(zhí)行
        6. 如果不是則說明鎖對象已經(jīng)被其他線程搶占。
        7. 如果出現(xiàn)兩條以上線程爭用同一個鎖,輕量級鎖就不再有效,將膨脹為重量級鎖,鎖標(biāo)志狀態(tài)變?yōu)?10,此時Mark Word 存儲的就是指向重量級鎖的指針,后面等待鎖的線程也必須阻塞。

        簡述鎖優(yōu)化策略

        即自適應(yīng)自旋、鎖消除、鎖粗化、鎖升級等策略偏。

        簡述java的自旋鎖

        線程獲取鎖失敗后,可以采用這樣的策略,可以不放棄 CPU ,不停的重試內(nèi)重試,這種操作也稱為自旋鎖。

        簡述自適應(yīng)自旋鎖

        自適應(yīng)自旋鎖自旋次數(shù)不再人為設(shè)定,通常由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態(tài)決定。

        簡述鎖粗化

        鎖粗化的思想就是擴大加鎖范圍,避免反復(fù)的加鎖和解鎖。

        簡述鎖消除

        鎖消除是一種更為徹底的優(yōu)化,在編譯時,java編譯器對運行上下文進行掃描,去除不可能存在共享資源競爭的鎖。

        簡述Lock與ReentrantLock

        Lock 接是 java并發(fā)包的頂層接口。

        可重入鎖 ReentrantLock 是 Lock 最常見的實現(xiàn),與 synchronized 一樣可重入。ReentrantLock 在默認情況下是非公平的,可以通過構(gòu)造方法指定公平鎖。一旦使用了公平鎖,性能會下降。

        簡述AQS

        AQS(AbstractQuenedSynchronizer)抽象的隊列式同步器。AQS是將每一條請求共享資源的線程封裝成一個鎖隊列的一個結(jié)點(Node),來實現(xiàn)鎖的分配。AQS是用來構(gòu)建鎖或其他同步組件的基礎(chǔ)框架,它使用一個 volatile int state 變量作為共享資源,如果線程獲取資源失敗,則進入同步隊列等待;如果獲取成功就執(zhí)行臨界區(qū)代碼,釋放資源時會通知同步隊列中的等待線程。

        子類通過繼承同步器并實現(xiàn)它的抽象方法getState、setState 和 compareAndSetState對同步狀態(tài)進行更改。

        AQS獲取獨占鎖/釋放獨占鎖原理

        獲?。海╝cquire)

        1. 調(diào)用 tryAcquire 方法安全地獲取線程同步狀態(tài),獲取失敗的線程會被構(gòu)造同步節(jié)點并通過 addWaiter 方法加入到同步隊列的尾部,在隊列中自旋。
        2. 調(diào)用 acquireQueued 方法使得該節(jié)點以死循環(huán)的方式獲取同步狀態(tài),如果獲取不到則阻塞。

        釋放:(release)

        1. 調(diào)用 tryRelease 方法釋放同步狀態(tài)
        2. 調(diào)用 unparkSuccessor 方法喚醒頭節(jié)點的后繼節(jié)點,使后繼節(jié)點重新嘗試獲取同步狀態(tài)。

        AQS獲取共享鎖/釋放共享鎖原理

        獲取鎖(acquireShared)

        1. 調(diào)用 tryAcquireShared 方法嘗試獲取同步狀態(tài),返回值不小于 0 表示能獲取同步狀態(tài)。

        釋放(releaseShared)

        1. 釋放,并喚醒后續(xù)處于等待狀態(tài)的節(jié)點。

        線程池類型

        1. newCachedThreadPool 可緩存線程池,可設(shè)置最小線程數(shù)和最大線程數(shù),線程空閑1分鐘后自動銷毀。
        2. newFixedThreadPool 指定工作線程數(shù)量線程池。
        3. newSingleThreadExecutor 單線程Executor。
        4. newScheduleThreadPool 支持定時任務(wù)的指定工作線程數(shù)量線程池。
        5. newSingleThreadScheduledExecutor 支持定時任務(wù)的單線程Executor。

        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 爽死777影院 | 中文字幕 乱伦 | 操逼黄片美女 | 性交综合网 | 午夜精品成人片免费 |