Java 八股文:JUC 篇

5 - JUC 篇

5.1 線程基礎(chǔ)

5.1.1 進(jìn)程愚战、線程與協(xié)程?
  1. 概念
    • 進(jìn)程:程序執(zhí)行的獨(dú)立實(shí)例齐遵,擁有自己的內(nèi)存空間寂玲。有多個(gè)狀態(tài),如運(yùn)行梗摇、等待拓哟、就緒和終止。
    • 線程:進(jìn)程中的一個(gè)實(shí)體伶授,是CPU調(diào)度的最小單位断序。同一進(jìn)程的線程共享進(jìn)程資源,如內(nèi)存糜烹。
    • 協(xié)程:輕量級(jí)線程违诗,用于非阻塞的異步編程【巴迹可以在等待操作時(shí)掛起较雕,節(jié)省資源,提高效率挚币。
  2. 區(qū)別
    • 進(jìn)程是正在運(yùn)行程序的 實(shí)例亮蒋,進(jìn)程中包含了線程,每個(gè)線程執(zhí)行不同的 任務(wù)妆毕。
    • 不同的進(jìn)程使用 不同 的內(nèi)存空間慎玖,在當(dāng)前進(jìn)程下的所有線程可以 共享 內(nèi)存空間。
    • 線程比進(jìn)程更輕量笛粘,線程上下文切換成本一般上要比進(jìn)程上下文切換低趁怔。
    • 協(xié)程比線程更輕量,適合處理大量并發(fā)的異步任務(wù)薪前。
5.1.2 并行與并發(fā)的區(qū)別润努?

并發(fā):

  • 并發(fā)是指多個(gè)任務(wù)在同一個(gè)時(shí)間段內(nèi)進(jìn)行,它們可能在不同的處理器上示括,也可能在同一個(gè)處理器上快速切換铺浇。
  • 在多線程環(huán)境中,即使只有一個(gè)CPU核心垛膝,線程也可以通過 時(shí)間片輪轉(zhuǎn) 實(shí)現(xiàn)并發(fā)執(zhí)行鳍侣。

并行:

  • 并行是指多個(gè)任務(wù)同時(shí)進(jìn)行丁稀,且每個(gè)任務(wù)都在不同的處理器上執(zhí)行。
  • 并行需要多個(gè)處理器或核心倚聚,這樣多個(gè)任務(wù)可以真正地 同時(shí)進(jìn)行线衫,而不是通過時(shí)間片輪轉(zhuǎn)。

區(qū)別:

  • 并發(fā)更側(cè)重于任務(wù)的重疊執(zhí)行惑折,而并行側(cè)重于任務(wù)的真正同時(shí)執(zhí)行授账。
  • 并發(fā)可能涉及I/O操作和CPU計(jì)算的交替,而并行則通常涉及多個(gè)計(jì)算任務(wù)的并發(fā)處理惨驶。
5.1.3 線程創(chuàng)建的方式有哪些矗积?
  1. 直接使用 Thread 類

    Thread t = new Thread(() -> { log.debug("running"); }, "t1");
    
  2. 使用 Runnable 接口配合 Thread

    Runnable r = () -> { log.debug("running"); };
    Thread t = new Thread(r, "t2");
    
  3. 使用 Callable 接口配合 Thread

    FutureTask<String> ft = new FutureTask<>(() -> {
        log.debug("running");
        return "Hello from Callable";
    });
    Thread t = new Thread(ft, "t3");
    
  4. 使用 ThreadPoolExecutor 線程池

    ExecutorService e = Executors.newFixedThreadPool(4);
    e.submit(() -> { log.debug("running"); });
    
5.1.4 Runnable 和 Callable 有什么區(qū)別?
  • Runnable 接口 run 方法沒有返回值敞咧。且異常只能在內(nèi)部消化,不允許拋出異常辜腺。
  • Callable 接口 call 方法有返回值休建,需要 FutureTask 獲取結(jié)果。且允許拋出異常评疗。
5.1.5 線程的 run() 和 start() 有什么區(qū)別测砂?
  • start():只能被調(diào)用一次,用來啟動(dòng)線程百匆。
  • run():可以被調(diào)用多次砌些,用來執(zhí)行封裝的代碼。
5.1.6 線程的生命周期 / 六種狀態(tài)

線程的六種狀態(tài)包括新建加匈、可運(yùn)行存璃、運(yùn)行、阻塞雕拼、等待纵东、計(jì)時(shí)等待和終止?fàn)顟B(tài)。

  1. 線程從 新建 狀態(tài)開始啥寇,通過調(diào)用 start() 方法進(jìn)入 可運(yùn)行 狀態(tài)偎球,等待操作系統(tǒng)分配時(shí)間片。
  2. 獲得時(shí)間片后辑甜,線程進(jìn)入 運(yùn)行 狀態(tài)執(zhí)行任務(wù)衰絮。
  3. 在運(yùn)行過程中,線程可能因?yàn)榈却i磷醋、調(diào)用 wait() 方法或 sleep() 方法而進(jìn)入 阻塞猫牡、等待計(jì)時(shí)等待 狀態(tài)。
  4. 當(dāng)線程完成任務(wù)或因異常結(jié)束時(shí)子檀,它將進(jìn)入 終止 狀態(tài)镊掖。
5.1.7 wait 和 sleep 方法的不同乃戈?
  • wait 的調(diào)用必須獲取 對(duì)象鎖,而 sleep 則不用亩进。

  • wait 是 Object 的成員方法症虑,執(zhí)行后 會(huì)釋放 對(duì)象鎖(其他人可以用)。

  • sleep 是 Thread 的靜態(tài)方法归薛,執(zhí)行后 不會(huì)釋放 對(duì)象鎖(其他人也用不了)谍憔。

5.1.8 新建三個(gè)線程,如何保證它們按順序執(zhí)行主籍?

通過在創(chuàng)建線程的順序中使用 join() 方法习贫,可以確保線程按照創(chuàng)建的順序執(zhí)行。

Thread t1 = new Thread(Runnable1);
Thread t2 = new Thread(Runnable2);
Thread t3 = new Thread(Runnable3);

t1.start();       t1.join();      // 等待t1執(zhí)行完成
t2.start();       t2.join();      // 等待t2執(zhí)行完成
t3.start();
5.1.9 notify() 和 notifyAll() 有什么區(qū)別千元?
  • notifyAll:喚醒所有 wait 的線程
  • notify:隨機(jī)喚醒一個(gè) wait 線程
5.1.10 如何停止一個(gè)正在運(yùn)行的線程苫昌?
  1. 使用 interrupt()線程的中斷狀態(tài)是一個(gè)標(biāo)志,可以通過 Thread.interrupt() 設(shè)置幸海,Thread.isInterrupted() 檢查祟身。
  2. 使用標(biāo)志變量:設(shè)置一個(gè)共享的標(biāo)志變量,線程定期檢查這個(gè)變量物独,如果變量被設(shè)置袜硫,則退出運(yùn)行。
  3. 使用 Future.cancel()如果線程是 ExecutorService 管理的挡篓,可以使用 Future.cancel() 方法來取消任務(wù)婉陷。

注意: 直接調(diào)用 stop() 方法來停止線程是不安全的,因?yàn)樗赡軐?dǎo)致資源泄露和不一致的狀態(tài)官研。

5.2 線程安全

5.2.1 Synchronized 原理及鎖升級(jí)秽澳?

1. Synchronized 底層原理

  1. Synchronized 對(duì)象鎖采用 互斥 的方式,讓同一時(shí)刻至多只有一個(gè)線程能持有對(duì)象鎖戏羽。
  2. 它的底層由 monitor 實(shí)現(xiàn)肝集,monitor 是 JVM 級(jí)別的對(duì)象( C++實(shí)現(xiàn)),內(nèi)部有三個(gè)屬性:
    • owner 關(guān)聯(lián)的是當(dāng)前獲得鎖的線程
    • entrylist 關(guān)聯(lián)的是處于阻塞狀態(tài)的線程隊(duì)列
    • waitset 關(guān)聯(lián)的是處于等待狀態(tài)的線程隊(duì)列

2. 鎖升級(jí)

  1. 重量級(jí)鎖:當(dāng)多個(gè)線程競(jìng)爭激烈時(shí)蛛壳,synchronized 會(huì)退化為重量級(jí)鎖杏瞻。

    重量級(jí)鎖通過操作系統(tǒng)的互斥鎖來實(shí)現(xiàn),涉及到用戶態(tài)和內(nèi)核態(tài)的切換衙荐,以及進(jìn)程上下文切換捞挥,會(huì)帶來較高的性能開銷。

  2. 輕量級(jí)鎖:在競(jìng)爭不激烈的情況下忧吟,synchronized 會(huì)使用輕量級(jí)鎖砌函。

    輕量級(jí)鎖主要通過CAS操作來嘗試獲取鎖,這是一種無鎖的非阻塞算法,它避免了較高的開銷讹俊,因此在低競(jìng)爭環(huán)境下性能較好垦沉。

  3. 偏向鎖:當(dāng)一個(gè)線程多次獲取同一個(gè)鎖時(shí),JVM會(huì)將這個(gè)鎖偏向這個(gè)線程仍劈,但在多線程競(jìng)爭時(shí)會(huì)升級(jí)為輕量級(jí)鎖或重量級(jí)鎖厕倍。

    即在該線程再次獲取鎖時(shí),會(huì)檢查對(duì)象頭的mark word中的線程ID贩疙,如果一致讹弯,則無需進(jìn)行CAS操作。

5.2.2 談一談 JVM(Java Virtual Machine)这溅?
  • JVM 是一個(gè)抽象計(jì)算機(jī)组民,它提供了一個(gè)運(yùn)行時(shí)環(huán)境,允許 Java 字節(jié)碼在任何平臺(tái)上運(yùn)行悲靴。
  • JVM 包括類加載器臭胜、運(yùn)行時(shí)數(shù)據(jù)區(qū)和執(zhí)行引擎。
  • 類加載器負(fù)責(zé)加載類文件癞尚,運(yùn)行時(shí)數(shù)據(jù)區(qū)包括堆庇楞、棧、方法區(qū)等否纬,執(zhí)行引擎則負(fù)責(zé)執(zhí)行字節(jié)碼。
5.2.3 談一談 CAS(Compare-And-Swap)蛋褥?
  • CAS 基于樂觀鎖的思想临燃,是一種無鎖的非阻塞算法,用于實(shí)現(xiàn)多線程下的原子操作烙心。
  • 它包含三個(gè)操作數(shù):內(nèi)存位置(V)膜廊、預(yù)期原值(A)和新值(B)。
  • 如果內(nèi)存位置的值與預(yù)期原值相匹配淫茵,那么處理器會(huì)自動(dòng)將該位置值更新為新值爪瓜。
5.2.4 談一談 AQS(AbstractQueuedSynchronizer)?
  • AQS 是一個(gè)用于構(gòu)建鎖和其他同步器的框架匙瘪,它提供了一套可擴(kuò)展的原子操作铆铆。
  • AQS 使用一個(gè)整數(shù)狀態(tài)來表示同步狀態(tài),通過內(nèi)置的FIFO隊(duì)列來管理線程丹喻。
  • AQS 提供了 acquire薄货、releasetryAcquiretryRelease 等方法碍论,允許自定義同步器實(shí)現(xiàn)自己的同步邏輯谅猾。
5.2.5 ReentrantLock 的實(shí)現(xiàn)原理?
  1. ReentrantLock 是一個(gè)可重入的互斥鎖,它基于 AQS 實(shí)現(xiàn)税娜。
  2. 它支持公平鎖和非公平鎖兩種模式坐搔,公平鎖會(huì)按照線程等待的順序獲取鎖,非公平鎖則可能造成饑餓敬矩。
  3. ReentrantLock 提供了 lock()概行、unlock()tryLock() 等方法谤绳,允許更靈活的鎖定操作占锯。
5.2.6 Synchronized 和 Lock 的區(qū)別?
  1. 語法層面
  • Synchronized 是 關(guān)鍵字缩筛,源碼在 jvm 中消略,用 c++ 語言實(shí)現(xiàn)。自動(dòng)釋放鎖瞎抛。
  • Lock 是 接口艺演,源碼由 jdk 提供,用 java 語言實(shí)現(xiàn)桐臊。手動(dòng)釋放鎖胎撤。
  1. 功能層面
  • Lock 提供了 Synchronized 不具備的功能,例如公平鎖断凶、可打斷伤提、可超時(shí)、多條件變量认烁。
  • Lock 有適合不同場(chǎng)景的實(shí)現(xiàn)肿男,如 ReentrantLockReentrantReadWriteLock(讀寫鎖)却嗡。
  1. 性能層面
  • 在沒有競(jìng)爭時(shí)舶沛,Synchronized 的性能一般,但輕量級(jí)鎖窗价、偏向鎖也不賴如庭。
  • 在競(jìng)爭激烈時(shí),Lock 的性能更好撼港。
5.2.7 死鎖的必要條件坪它?
  • 線程是程序執(zhí)行的最小單位,鎖用于同步線程間的資源訪問帝牡。一個(gè)線程需要同時(shí)獲取多把鎖哟楷,就容易發(fā)生死鎖。

  • 死鎖的四個(gè)必要條件:互斥否灾、占有和等待卖擅、不可剝奪、環(huán)路等待。

  • 如何避免:避免循環(huán)等待惩阶,確保資源有序分配等挎狸。

5.2.8 如何進(jìn)行死鎖診斷?
  1. jps:jdk 自帶工具断楷,檢查進(jìn)程的狀態(tài)信息锨匆。
  2. jstack:jdk 自帶工具,檢查線程的堆棧信息冬筒,查看日志恐锣。
  3. jconsoleVisualVM:可視化工具舞痰,也可以檢查死鎖問題土榴。
5.2.9 請(qǐng)談?wù)勀銓?duì) volatile 的理解?
  1. 保證線程間的可見性响牛。用 volatile 修飾共享變量玷禽,能夠防止編譯器的優(yōu)化,讓一個(gè)線程對(duì)共享變量的修改對(duì)另一個(gè)線程可見呀打。
  2. 禁止進(jìn)行指令重排序矢赁。用 volatile 修飾共享變量,會(huì)加入不同的屏障贬丛,阻止其他讀寫操作越過屏障撩银。
5.2.10 并發(fā)問題的根本原因?
  1. 并發(fā)問題的根本原因
    • 沒有保證原子性:一個(gè)線程在 CPU 中操作不可暫停豺憔,也不可中斷额获。解決:synchronizedlock焕阿。
    • 沒有保證可見性:讓一個(gè)線程對(duì)共享變量的修改對(duì)另一個(gè)線程可見。解決:volatile首启、synchronized暮屡、lock
    • 沒有保證有序性:因?yàn)樘幚砥鳛榱颂岣哌\(yùn)行效率毅桃,對(duì)代碼進(jìn)行了優(yōu)化而無序褒纲。解決:volatile
  2. volatile 的理解
    • 保證線程間的可見性钥飞。volatile 修飾共享變量能防止編譯器的優(yōu)化莺掠,讓一個(gè)線程對(duì)共享變量的修改對(duì)另一個(gè)線程可見。
    • 禁止進(jìn)行指令重排序读宙。volatile 修飾共享變量會(huì)加入不同的屏障彻秆,阻止其他讀寫操作越過屏障。
5.2.11 Synchronized 用于靜態(tài)方法與普通方法的區(qū)別?

1. 鎖的對(duì)象

  • 對(duì)于普通方法唇兑,鎖的對(duì)象是調(diào)用該方法的實(shí)例對(duì)象(即 this)酒朵。
  • 對(duì)于靜態(tài)方法,鎖的對(duì)象是當(dāng)前類的 Class 對(duì)象扎附。

2. 影響范圍

  • 對(duì)于普通方法蔫耽,鎖的范圍是實(shí)例對(duì)象級(jí)別的,即每個(gè)實(shí)例對(duì)象有自己的鎖留夜。
  • 對(duì)于靜態(tài)方法匙铡,鎖的范圍是類級(jí)別的,即所有該類的實(shí)例對(duì)象共享同一個(gè)鎖碍粥。

3. 性能影響

  • 靜態(tài)方法的鎖通常比普通方法的鎖開銷更小鳖眼,因?yàn)樗i定的是類而不是實(shí)例對(duì)象。
5.2.12 樂觀鎖和悲觀鎖的區(qū)別即纲?
  1. 樂觀鎖:

    • 樂觀鎖假設(shè)沖突很少發(fā)生具帮,通常通過檢測(cè)在操作過程中數(shù)據(jù)是否被其他線程修改來實(shí)現(xiàn)。

    • 它適用于 讀多寫少 的場(chǎng)景低斋,常見的實(shí)現(xiàn)方式是使用版本號(hào)或時(shí)間戳蜂厅。

  2. 悲觀鎖:

    • 悲觀鎖假設(shè)沖突經(jīng)常發(fā)生,通常在操作數(shù)據(jù)時(shí)直接加鎖膊畴。

    • 它適用于 寫操作頻繁 的場(chǎng)景掘猿,可以防止數(shù)據(jù)不一致,但可能導(dǎo)致線程阻塞和性能下降唇跨。

5.3 線程池

5.3.1 線程池創(chuàng)建及執(zhí)行流程稠通?
  1. ThreadPoolExecutor 創(chuàng)建線程池的核心參數(shù):

    • corePoolSize:核心線程數(shù)目

    • maximumPoolSize:最大線程數(shù)目 = 核心線程數(shù)目 + 非核心線程數(shù)目

    • keepAliveTime:生存時(shí)間,生存時(shí)間內(nèi)沒有新任務(wù)买猖,此線程資源會(huì)釋放

    • unit:生存時(shí)間單位改橘,如秒、毫秒等

    • workQueue:阻塞隊(duì)列玉控,當(dāng)沒有空閑核心線程時(shí)飞主,新來任務(wù)會(huì)加入到此隊(duì)列排隊(duì)

    • threadFactory:線程工廠,可以定制線程對(duì)象的創(chuàng)建高诺,例如設(shè)置線程名字

    • handler:拒絕策略碌识,當(dāng)所有線程都在忙,阻塞隊(duì)列也放滿時(shí)虱而,會(huì)觸發(fā)拒絕策略

  2. 線程池的執(zhí)行原理:

5.3.2 線程池的 BlockingQueue筏餐?如何體現(xiàn)阻塞?
  • 有界隊(duì)列是指隊(duì)列有固定的大小牡拇,當(dāng)隊(duì)列滿了之后魁瞪,新的任務(wù)將不能被提交穆律,除非隊(duì)列中的任務(wù)被消費(fèi)。

  • 無界隊(duì)列則沒有固定的大小限制佩番,理論上可以無限增長众旗,直到內(nèi)存耗盡。

LinkedBlockingQueue ArrayBlockingQueue
默認(rèn)無界趟畏,支持有界 強(qiáng)制有界
底層是鏈表 底層是數(shù)組
是懶惰的贡歧,創(chuàng)建節(jié)點(diǎn)的時(shí)候添加數(shù)據(jù) 提前初始化 Node 數(shù)組
入隊(duì)會(huì)創(chuàng)建新 Node Node 需要提前創(chuàng)建好
兩把鎖(頭尾) 一把鎖
  1. 線程提交任務(wù)到隊(duì)列時(shí):如果已滿,put()offer()方法會(huì)阻塞當(dāng)前線程赋秀,直到隊(duì)列中有空間可用利朵。
  2. 線程從隊(duì)列獲取任務(wù)時(shí):如果為空,take()poll()方法會(huì)阻塞當(dāng)前線程猎莲,直到隊(duì)列中有任務(wù)可用绍弟。
5.3.3 如何確定核心線程數(shù)?
  • 并發(fā)較高著洼、任務(wù)執(zhí)行時(shí)間短:

    • CPU 核數(shù) + 1樟遣,減少線程上下文的切換。
  • 并發(fā)不高身笤、任務(wù)執(zhí)行時(shí)間長:

    • IO 密集型的任務(wù):CPU核數(shù) * 2 + 1豹悬。
    • 計(jì)算密集型任務(wù):CPU核數(shù) + 1
5.3.4 線程池的種類有哪些液荸?
  1. newFixedThreadPool:**定長 **的線程池瞻佛,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待娇钱。
  2. newSingleThreadExecutor:**單線程 **化的線程池伤柄,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按 FIFO 順序執(zhí)行文搂。
  3. newCachedThreadPool可緩存 的線程池适刀,如果線程池長度超過處理需要,可靈活回收空閑線程煤蹭,若無可回收笔喉,則新建線程。
  4. newScheduledThreadPool:可執(zhí)行 延遲任務(wù) 的線程池疯兼,支持定時(shí)及周期性任務(wù)執(zhí)行然遏。
5.3.5 為什么不建議用 Executors 創(chuàng)建線程池贫途?

線程池不建議使用 Executors 創(chuàng)建吧彪,而是通過 ThreadPoolExecutor,可以規(guī)避資源耗盡的風(fēng)險(xiǎn)丢早。分析源碼:

  1. FixedThreadPool 和 SingleThreadPool:允許的請(qǐng)求隊(duì)列長度為 Integer.MAXVALUE姨裸,可能堆積 大量請(qǐng)求秧倾,從而導(dǎo)致 OOM。
  2. CachedThreadPool:允許的創(chuàng)建線程數(shù)量為 Integer.MAXVALUE傀缩,可能創(chuàng)建 大量線程那先,從而導(dǎo)致 OOM。
5.3.6 線程池的拒絕策略有哪些赡艰?

線程池的拒絕策略就是當(dāng)線程池忙不過來售淡,任務(wù)太多,隊(duì)列都滿了准谚,它怎么處理新來的任務(wù)弹惦。Java里有幾個(gè)招兒:

  1. AbortPolicy:這個(gè)策略就是直接說“不”账胧,如果新任務(wù)來了,它就直接拋出一個(gè)異常汤纸,告訴你“不行,我忙不過來了”芹血。

  2. CallerRunsPolicy:這個(gè)策略比較溫和贮泞,它會(huì)告訴提交任務(wù)的線程說“你等等,我先幫你跑這個(gè)任務(wù)”幔烛。

    但是啃擦,如果線程池已經(jīng)關(guān)了,它就不管了说贝。這個(gè)策略可能會(huì)讓程序變慢议惰,但是如果真的需要每個(gè)任務(wù)被處理,可以用這個(gè)乡恕。

  3. DiscardPolicy:這個(gè)策略就是“無視”言询,新任務(wù)來了,它看都不看傲宜,直接扔掉运杭,不處理。

  4. DiscardOldestPolicy:這個(gè)策略有點(diǎn)“喜新厭舊”函卒,它會(huì)看隊(duì)列里哪個(gè)任務(wù)最老辆憔,然后把老任務(wù)扔掉,給新任務(wù)騰地方报嵌。

5.3.7 線程池的作用虱咧?
  1. 資源優(yōu)化:線程池通過重用已經(jīng)創(chuàng)建的線程來執(zhí)行新的任務(wù),避免了頻繁創(chuàng)建和銷毀線程的開銷锚国,從而優(yōu)化了系統(tǒng)資源的使用腕巡。
  2. 提高性能:線程池減少線程創(chuàng)建和銷毀的開銷,因?yàn)閯?chuàng)建和銷毀是耗時(shí)的過程血筑,線程池可以提高程序的響應(yīng)速度和吞吐量绘沉。
  3. 控制并發(fā):線程池限制程序中同時(shí)運(yùn)行的線程數(shù)量煎楣,避免線程過多而系統(tǒng)過載和資源競(jìng)爭,從而提高系統(tǒng)穩(wěn)定性和響應(yīng)能力车伞。
  4. 提高線程管理的簡便性:線程池提供了統(tǒng)一的線程管理機(jī)制择懂,使得線程的創(chuàng)建、調(diào)度另玖、執(zhí)行和銷毀更加方便和高效困曙。
  5. 異常和任務(wù)管理:線程池集中處理線程執(zhí)行中出現(xiàn)的異常,并且對(duì)任務(wù)進(jìn)行調(diào)度和優(yōu)先級(jí)管理谦去,使得任務(wù)執(zhí)行更加有序和可控赂弓。

5.4 使用場(chǎng)景

5.4.1 線程池使用場(chǎng)景?
  1. 資源管理: 線程池可以限制并發(fā)線程的數(shù)量哪轿,有效管理資源盈魁。
  2. 提高響應(yīng)速度: 線程池可以減少線程創(chuàng)建和銷毀的開銷,快速響應(yīng)任務(wù)請(qǐng)求窃诉。
  3. 提高線程的可管理性: 線程池提供了線程的統(tǒng)一管理杨耙,包括線程的創(chuàng)建、銷毀和監(jiān)控飘痛。
  4. 控制并發(fā)級(jí)別: 在需要控制并發(fā)任務(wù)數(shù)量的場(chǎng)景下珊膜,線程池可以限制同時(shí)運(yùn)行的線程數(shù)量。
5.4.2 如何控制某個(gè)方法允許并發(fā)訪問線程的數(shù)量宣脉?

在多線程中提供了一個(gè)工具類 Semaphore车柠,信號(hào)量。在并發(fā)的情況下塑猖,可以控制方法的訪問量:

  1. 創(chuàng)建 Semaphore 對(duì)象竹祷,可以給一個(gè)容量。
  2. acquire() 可以請(qǐng)求一個(gè)信號(hào)量羊苟,此時(shí)信號(hào)量個(gè)數(shù) - 1塑陵。
  3. release() 可以釋放一個(gè)信號(hào)量,此時(shí)信號(hào)量個(gè)數(shù) + 1蜡励。
5.4.3 談?wù)?ThreadLocal令花?
  1. ThreadLocal 實(shí)現(xiàn)了資源對(duì)象的線程隔離,讓每個(gè)線程各用各的凉倚,避免爭用 引發(fā)線程安全問題兼都。
    • 就像每個(gè)線程都把物品放在私人儲(chǔ)物柜里,別的線程看不到也拿不到稽寒,就不會(huì)因?yàn)榇蠹叶枷胗猛粯訓(xùn)|西而打架扮碧。
  2. ThreadLocal 實(shí)現(xiàn)了線程內(nèi)的 資源共享。每個(gè)線程內(nèi)有一個(gè) ThreadLocalMap 類型的成員變量:
    • 調(diào)用 set 方法瓦胎,以 ThreadLocal 作為 key芬萍,以資源對(duì)象作為 value 存入。
    • 調(diào)用 get 方法搔啊,以 ThreadLocal 作為 key柬祠,以資源對(duì)象作為 value 取出。
  3. 內(nèi)存泄漏 問題:key 是弱引用负芋,會(huì)被 GC 釋放內(nèi)存漫蛔。而 value 是強(qiáng)引用,不會(huì)釋放旧蛾。建議主動(dòng)調(diào)用 remove 釋放莽龟。
    • 就像如果有人吃完了飯,但是忘記把自己的餐具放回原位锨天,這些餐具就會(huì)一直占用空間毯盈,這就是所謂的“內(nèi)存泄漏”。
    • ThreadLocal 里病袄,如果你不再需要某個(gè)線程的資源搂赋,但是沒有手動(dòng)清理,那么這些資源就會(huì)一直占用內(nèi)存益缠。
    • 因?yàn)?key(儲(chǔ)物柜號(hào)碼)是弱引用脑奠,可能會(huì)被垃圾回收器清理掉,但是 value(物品)是強(qiáng)引用幅慌,不會(huì)被自動(dòng)清理宋欺。
5.4.4 Java 中有哪些類型的鎖?
  • 鎖的應(yīng)用場(chǎng)景

    • 對(duì)象鎖(Synchronized)適用于保護(hù)單個(gè)對(duì)象實(shí)例的訪問胰伍。

    • 類鎖(Synchronized)適用于控制對(duì)類級(jí)別資源的訪問齿诞,如靜態(tài)變量。

    • 重入鎖(ReentrantLock)適用于需要復(fù)雜同步控制的場(chǎng)景骂租。

    • 讀寫鎖(ReentrantReadWriteLock)適用于讀操作頻繁且寫操作較少的場(chǎng)景掌挚。

    • 自旋鎖(Spin Lock)適用于鎖持有時(shí)間短且競(jìng)爭激烈度低的場(chǎng)景。

  • 鎖的性能比較

    • Synchronized經(jīng)過 JVM 優(yōu)化菩咨,性能較高吠式,但可能導(dǎo)致線程阻塞。

    • ReentrantLock提供更多功能抽米,但性能略低于Synchronized特占。

    • ReentrantReadWriteLock適用于讀多寫少,提高讀操作并發(fā)性云茸。

    • SpinLock適用于鎖保護(hù)時(shí)間短是目,避免上下文切換開銷,但可能導(dǎo)致CPU消耗标捺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末懊纳,一起剝皮案震驚了整個(gè)濱河市揉抵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗤疯,老刑警劉巖冤今,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異茂缚,居然都是意外死亡戏罢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脚囊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來龟糕,“玉大人,你說我怎么就攤上這事悔耘〗菜辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵衬以,是天一觀的道長催首。 經(jīng)常有香客問我,道長泄鹏,這世上最難降的妖魔是什么郎任? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮备籽,結(jié)果婚禮上舶治,老公的妹妹穿的比我還像新娘。我一直安慰自己车猬,他們只是感情好霉猛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著珠闰,像睡著了一般惜浅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伏嗜,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天坛悉,我揣著相機(jī)與錄音,去河邊找鬼承绸。 笑死裸影,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的军熏。 我是一名探鬼主播轩猩,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了均践?” 一聲冷哼從身側(cè)響起晤锹,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎彤委,沒想到半個(gè)月后鞭铆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葫慎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薇宠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偷办。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖澄港,靈堂內(nèi)的尸體忽然破棺而出椒涯,到底是詐尸還是另有隱情,我是刑警寧澤回梧,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布废岂,位于F島的核電站,受9級(jí)特大地震影響狱意,放射性物質(zhì)發(fā)生泄漏湖苞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一详囤、第九天 我趴在偏房一處隱蔽的房頂上張望财骨。 院中可真熱鬧,春花似錦藏姐、人聲如沸隆箩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捌臊。三九已至,卻和暖如春兜材,著一層夾襖步出監(jiān)牢的瞬間理澎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工曙寡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矾端,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓卵皂,卻偏偏與公主長得像秩铆,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容