<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 多線程,八股文!

          共 9111字,需瀏覽 19分鐘

           ·

          2021-08-29 23:44

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

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

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

          簡(jiǎn)述as-if-serial

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

          簡(jiǎn)述happens-before八大原則

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

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

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

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

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

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

          對(duì)象終結(jié)規(guī)則:對(duì)象的初始化先行發(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é)果不變。

          簡(jiǎn)述原子性操作

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

          簡(jiǎn)述線程的可見(jiàn)性

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

          簡(jiǎn)述有序性

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

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

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

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

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

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

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

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

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

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

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

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

          簡(jiǎn)述線程通信的方式

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

          簡(jiǎn)述線程池

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

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

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

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

          2. 如果核心線程池已滿,工作隊(duì)列未滿,將線程存儲(chǔ)在工作隊(duì)列。

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

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

          線程池參數(shù)

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

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

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

          4. workQueue:工作隊(duì)列。

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

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

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

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

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

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

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

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

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

          簡(jiǎn)述Executor框架

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

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

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

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

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

          簡(jiǎn)述阻塞隊(duì)列

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

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

          談一談ThreadLocal

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

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

          存在的問(wèn)題

          1. 對(duì)于線程池,由于線程池會(huì)重用 Thread 對(duì)象,因此與 Thread 綁定的 ThreadLocal 也會(huì)被重用,造成一系列問(wèn)題。

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

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

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

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

          JAVA中的樂(lè)觀鎖與CAS算法

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

          到了寫(xiě)操作時(shí)才會(huì)進(jìn)行判斷,數(shù)據(jù)在此期間是否被其他線程修改。如果發(fā)生修改,那就返回寫(xiě)入失?。蝗绻麤](méi)有被修改,那就執(zhí)行修改操作,返回修改成功。

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

          CAS 算法的思路如下:

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

          ABA問(wèn)題及解決方法簡(jiǎn)述

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

          juc 包提供了一個(gè) AtomicStampedReference,即在原始的版本下加入版本號(hào)戳,解決 ABA 問(wèn)題。

          簡(jiǎn)述常見(jiàn)的Atomic類

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

          • AtomicInteger 原子更新整形
          • AtomicLong 原子更新長(zhǎng)整型
          • AtomicBoolean 原子更新布爾類型

          Atomic數(shù)組類型有:

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

          Atomic引用類型有

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

          FieldUpdater類型:

          • AtomicIntegerFieldUpdater 原子更新整形字段的更新器
          • AtomicLongFieldUpdater 原子更新長(zhǎng)整形字段的更新器
          • AtomicReferenceFieldUpdater 原子更新引用類型字段的更新器

          簡(jiǎn)述Atomic類基本實(shí)現(xiàn)原理

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

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

          簡(jiǎn)述CountDownLatch

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

          簡(jiǎn)述CyclicBarrier

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

          簡(jiǎn)述Semaphore

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

          簡(jiǎn)述Exchanger

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

          簡(jiǎn)述ConcurrentHashMap

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

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

          JDK8的改進(jìn)

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

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

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

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

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

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

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

          簡(jiǎn)述java偏向鎖

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

          其申請(qǐng)流程為:

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

          簡(jiǎn)述輕量級(jí)鎖

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

          其申請(qǐng)流程為:

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

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

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

          簡(jiǎn)述java的自旋鎖

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

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

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

          簡(jiǎn)述鎖粗化

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

          簡(jiǎn)述鎖消除

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

          簡(jiǎn)述Lock與ReentrantLock

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

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

          簡(jiǎn)述AQS

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

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

          AQS獲取獨(dú)占鎖/釋放獨(dú)占鎖原理

          獲?。海╝cquire)

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

          釋放:(release)

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

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

          獲取鎖(acquireShared)

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

          釋放(releaseShared)

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

          線程池類型

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

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级三级久久三级 | 亚洲中文字幕在线观看 | 销魂少妇一二三区 | 日韩欧美天堂 | 日日噜狠狠色综合久 |