【Java EE】JUC(java.util.concurrent) 的常見類

目錄

  • 🌴Callable 接口
  • 🎍ReentrantLock
  • 🍀原子類
  • 🌳線程池
  • 🌲信號量 Semaphore
  • ??CountDownLatch、
  • ?相關面試題

🌴Callable 接口

Callable 是?個 interface . 相當于把線程封裝了?個 “返回值”. ?便程序猿借助多線程的?式計算結
.

**代碼示例: **

創建線程計算 1 + 2 + 3 + … + 1000, 不使? Callable 版本。

? 創建?個類 Result , 包含?個 sum 表?最終結果, lock 表?線程同步使?的鎖對象.
? main ?法中先創建 Result 實例, 然后創建?個線程 t. 在線程內部計算 1 + 2 + 3 + … + 1000.
? 主線程同時使? wait 等待線程 t 計算結束. (注意, 如果執?到 wait 之前, 線程 t 已經計算完了, 就不
必等待了).
? 當線程 t 計算完畢后, 通過 notify 喚醒主線程, 主線程再打印結果.

public class Demo {static class Result {public int sum = 0;public Object lock = new Object();}public static void main(String[] args) throws InterruptedException {Result result = new Result();Thread t = new Thread() {@Overridepublic void run() {int sum = 0;for (int i = 1; i <= 1000; i++) {sum += i;}synchronized (result.lock) {result.sum = sum;result.lock.notify();}}};t.start();synchronized (result.lock) {while (result.sum == 0) {result.lock.wait();}System.out.println(result.sum);}}
}

可以看到, 上述代碼需要?個輔助類 Result, 還需要使??系列的加鎖和 wait notify 操作, 代碼復雜,
容易出錯.

使? Callable 版本代碼示例

? 創建?個匿名內部類, 實現 Callable 接?. Callable 帶有泛型參數. 泛型參數表?返回值的類型.
? 重寫 Callable 的 call ?法, 完成累加的過程. 直接通過返回值返回計算結果.
? 把 callable 實例使? FutureTask 包裝?下.
? 創建線程, 線程的構造?法傳? FutureTask . 此時新線程就會執? FutureTask 內部的 Callable 的
call ?法, 完成計算. 計算結果就放到了 FutureTask 對象中.
? 在主線程中調? futureTask.get() 能夠阻塞等待新線程計算完畢. 并獲取到 FutureTask 中的
結果.

public class CallableTest {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for(int i = 1; i<=1000; i++){sum+=i;}return sum;}};FutureTask<Integer> futuretask = new FutureTask<>(callable);Thread t = new Thread(futuretask);t.start();int result = futuretask.get();System.out.println(result);}
}

可以看到, 使? Callable 和 FutureTask 之后, 代碼簡化了很多, 也不必?動寫線程同步代碼了.

理解 Callable

Callable 和 Runnable 相對, 都是描述?個 “任務”. Callable 描述的是帶有返回值的任務, Runnable
描述的是不帶返回值的任務
.

Callable 通常需要搭配 FutureTask 來使?. FutureTask ?來保存 Callable 的返回結果. 因為
Callable 往往是在另?個線程中執?的, 啥時候執?完并不確定.

FutureTask 就可以負責這個等待結果出來的?作.

理解 FutureTask

想象去吃?辣燙. 當餐點好后, 后廚就開始做了. 同時前臺會給你?張 “?票” . 這個?票就是
FutureTask. 后?我們可以隨時憑這張?票去查看??的這份?辣燙做出來了沒.

🎍ReentrantLock

可重?互斥鎖. 和 synchronized 定位類似, 都是?來實現互斥效果, 保證線程安全.

ReentrantLock 也是可重?鎖. “Reentrant” 這個單詞的原意就是 “可重?”

ReentrantLock 的?法:
? lock(): 加鎖, 如果獲取不到鎖就死等.
? trylock(超時時間): 加鎖, 如果獲取不到鎖, 等待?定的時間之后就放棄加鎖.
? unlock(): 解鎖

ReentrantLock lock = new ReentrantLock(); 
-----------------------------------------
lock.lock(); 
try { // working 
} finally { lock.unlock() 
}

ReentrantLock 和 synchronized 的區別:

? synchronized 是?個關鍵字, 是 JVM 內部實現的(?概率是基于 C++ 實現). ReentrantLock 是標準
庫的?個類, 在 JVM 外實現的(基于 Java 實現).
? synchronized 使?時不需要?動釋放鎖. ReentrantLock 使?時需要?動釋放. 使?起來更靈活, 但
是也容易遺漏 unlock.
? synchronized 在申請鎖失敗時, 會死等. ReentrantLock 可以通過 trylock 的?式等待?段時間就放
棄.
? synchronized 是?公平鎖, ReentrantLock 默認是?公平鎖. 可以通過構造?法傳??個 true 開啟
公平鎖模式.

// ReentrantLock 的構造?法
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

? 更強?的喚醒機制. synchronized 是通過 Object 的 wait / notify 實現等待-喚醒. 每次喚醒的是?個
隨機等待的線程. ReentrantLock 搭配 Condition 類實現等待-喚醒, 可以更精確控制喚醒某個指定
的線程.

如何選擇使?哪個鎖?
? 鎖競爭不激烈的時候, 使? synchronized, 效率更?, ?動釋放更?便.
? 鎖競爭激烈的時候, 使? ReentrantLock, 搭配 trylock 更靈活控制加鎖的?為, ?不是死等.
? 如果需要使?公平鎖, 使? ReentrantLock

🍀原子類

原?類內部?的是 CAS 實現,所以性能要?加鎖實現 i++ ?很多。原?類有以下?個
? AtomicBoolean
? AtomicInteger
? AtomicIntegerArray
? AtomicLong
? AtomicReference
? AtomicStampedReference

以 AtomicInteger 舉例,常??法有

addAndGet(int delta); i += delta;
decrementAndGet(); --i;
getAndDecrement(); i--;
incrementAndGet(); ++i;
getAndIncrement(); i++;

使用示例:

public class AtomicTest {static AtomicInteger count = new AtomicInteger();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 5000; i++) {count.getAndIncrement();}});Thread t2 = new Thread(()->{for (int i = 0; i < 5000; i++) {count.getAndIncrement();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count.get());}
}

🌳線程池

雖然創建銷毀線程?創建銷毀進程更輕量, 但是在頻繁創建銷毀線程的時候還是會?較低效.

線程池就是為了解決這個問題. 如果某個線程不再使?了, 并不是真正把線程釋放, ?是放到?個 “池
?” 中, 下次如果需要?到線程就直接從池?中取, 不必通過系統來創建了.

ExecutorService 和 Executors

關于線程池這部分大家可以看博主之前的線程池詳解

🌲信號量 Semaphore

信號量, ?來表? “可?資源的個數”. 本質上就是?個計數器

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

Semaphore 的 PV 操作中的加減計數器操作都是原?的, 可以在多線程環境下直接使?.

代碼?例
? 創建 Semaphore ?例, 初始化為 4, 表?有 4 個可?資源.
? acquire ?法表?申請資源(P操作), release ?法表?釋放資源(V操作)
? 創建 20 個線程, 每個線程都嘗試申請資源, sleep 1秒之后, 釋放資源. 觀察程序的執?效果.

public class Test {public static void main(String[] args) {Semaphore semaphore = new Semaphore(4);Runnable runnable = new Runnable() {@Overridepublic void run() {try {System.out.println("申請資源");semaphore.acquire();System.out.println("我獲取到資源了");Thread.sleep(1000);System.out.println("我釋放資源了");semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}};for (int i = 0; i < 20; i++) {Thread t = new Thread(runnable);t.start();}}

??CountDownLatch、

同時等待 N 個任務執?結束.

好像跑步?賽,10個選?依次就位,哨聲響才同時出發;所有選?都通過終點,才能公布成績。

? 構造 CountDownLatch 實例, 初始化 10 表?有 10 個任務需要完成.
? 每個任務執?完畢, 都調? latch.countDown() . 在 CountDownLatch 內部的計數器同時?
減.
? 主線程中使? latch.await(); 阻塞等待所有任務執?完畢. 相當于計數器為 0 了.

public class Demo {public static void main(String[] args) throws Exception {CountDownLatch latch = new CountDownLatch(10);Runnable r = new Runable() {@Overridepublic void run() {try {Thread.sleep(Math.random() * 10000);latch.countDown();} catch (Exception e) {e.printStackTrace();}}};for (int i = 0; i < 10; i++) {new Thread(r).start();}// 必須等到 10 ?全部回來latch.await();System.out.println("?賽結束");}
}

?相關面試題

  1. 線程同步的?式有哪些?

synchronized, ReentrantLock, Semaphore 等都可以?于線程同步

  1. 為什么有了 synchronized 還需要 juc 下的 lock?

以 juc 的 ReentrantLock 為例,

? synchronized 使?時不需要?動釋放鎖. ReentrantLock 使?時需要?動釋放. 使?起來更靈活,
? synchronized 在申請鎖失敗時, 會死等. ReentrantLock 可以通過 trylock 的?式等待?段時間就放
棄.
? synchronized 是?公平鎖, ReentrantLock 默認是?公平鎖. 可以通過構造?法傳??個 true 開啟
公平鎖模式.
? synchronized 是通過 Object 的 wait / notify 實現等待-喚醒. 每次喚醒的是?個隨機等待的線程.
ReentrantLock 搭配 Condition 類實現等待-喚醒, 可以更精確控制喚醒某個指定的線程.

  1. AtomicInteger 的實現原理是什么?

基于 CAS 機制. 偽代碼如下:

class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {oldValue = value;}return oldValue;}
}

執?過程參考 “CAS詳解與應用” 博客.

  1. 信號量聽說過么?之前都?在過哪些場景下?

信號量, ?來表? “可?資源的個數”. 本質上就是?個計數器.
比特就業課
使?信號量可以實現 “共享鎖”, ?如某個資源允許 3 個線程同時使?, 那么就可以使? P 操作作為加
鎖, V 操作作為解鎖, 前三個線程的 P 操作都能順利返回, 后續線程再進? P 操作就會阻塞等待, 直到前
?的線程執?了 V 操作.

  1. 解釋?下 ThreadPoolExecutor 構造?法的參數的含義

參考博主的 線程池詳解 博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/716825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/716825.shtml
英文地址,請注明出處:http://en.pswp.cn/news/716825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

什么是灰色預測

灰色預測是一種基于灰色系統理論的預測方法&#xff0c;用于處理數據不完全、信息不充分或未知的情況下的預測問題。它適用于樣本數據較少、無法建立精確的數學模型的情況。 灰色預測的基本思想是利用已知數據的特點和規律來推斷未知數據的發展趨勢。它的核心是灰色關聯度的概念…

(學習日記)2024.03.01:UCOSIII第三節 + 函數指針 (持續更新文件結構)

寫在前面&#xff1a; 由于時間的不足與學習的碎片化&#xff0c;寫博客變得有些奢侈。 但是對于記錄學習&#xff08;忘了以后能快速復習&#xff09;的渴望一天天變得強烈。 既然如此 不如以天為單位&#xff0c;以時間為順序&#xff0c;僅僅將博客當做一個知識學習的目錄&a…

Kubernetes: 本地部署dashboard

本篇文章主要是介紹如何在本地部署kubernetes dashboard, 部署環境是mac m2 下載dashboard.yaml 官網release地址: kubernetes/dashboard/releases 本篇文章下載的是kubernetes-dashboard-v2.7.0的版本&#xff0c;通過wget命令下載到本地: wget https://raw.githubusercont…

【Python】進階學習:pandas--isin()用法詳解

【Python】進階學習&#xff1a;pandas–isin()用法詳解 &#x1f308; 個人主頁&#xff1a;高斯小哥 &#x1f525; 高質量專欄&#xff1a;Matplotlib之旅&#xff1a;零基礎精通數據可視化、Python基礎【高質量合集】、PyTorch零基礎入門教程&#x1f448; 希望得到您的訂閱…

【NDK系列】Android tombstone文件分析

文件位置 data/tombstone/tombstone_xx.txt 獲取tombstone文件命令&#xff1a; adb shell cp /data/tombstones ./tombstones 觸發時機 NDK程序在發生崩潰時&#xff0c;它會在路徑/data/tombstones/下產生導致程序crash的文件tombstone_xx&#xff0c;記錄了死亡了進程的…

單細胞Seurat - 細胞聚類(3)

本系列持續更新Seurat單細胞分析教程&#xff0c;歡迎關注&#xff01; 維度確定 為了克服 scRNA-seq 數據的任何單個特征中廣泛的技術噪音&#xff0c;Seurat 根據 PCA 分數對細胞進行聚類&#xff0c;每個 PC 本質上代表一個“元特征”&#xff0c;它結合了相關特征集的信息。…

深入測探:用Python玩轉分支結構與循環操作——技巧、場景及面試寶典

在編程的世界里&#xff0c;分支結構和循環操作是構建算法邏輯的基礎磚石。它們如同編程的“鹽”&#xff0c;賦予代碼生命&#xff0c;讓靜態的數據跳躍起來。本文將帶你深入探索Python中的分支結構和循環操作&#xff0c;通過精心挑選的示例和練習題&#xff0c;不僅幫助你掌…

mysql5*-mysql8 區別

1.Mysql5.7-Mysql8.0 sysbench https://github.com/geekgogie/mysql57_vs_8-benchmark_scripts 1.讀、寫、刪除更新 速度 512 個線程以后才會出現如下的。 2.刪除速度 2.事務處理性能 3.CPU利用率 mysql8 利用率高。 4.排序 5.7 只能ASC&#xff0c;不能降序 數據越來越大

牢記于心單獨說出來的知識點(后續會加)

第一個 非十進制&#xff08;八進制&#xff0c;十六進制&#xff09;寫在文件中它本身就是補碼&#xff0c;計算機是不用進行內存轉換&#xff0c;它直接存入內存。&#xff08;因為十六進制本身是補碼&#xff0c;所以計算機里面我們看到的都是十六進制去存儲&#xff09; …

Qt 簡約美觀的加載動畫 文本風格 第八季

今天和大家分享一個文本風格的加載動畫, 有兩類,其中一個可以設置文本內容和文本顏色,演示了兩份. 共三個動畫, 效果如下: 一共三個文件,可以直接編譯 , 如果對您有所幫助的話 , 不要忘了點贊呢. //main.cpp #include "LoadingAnimWidget.h" #include <QApplic…

MySQL:開始深入其數據(一)DML

在上一章初識MySQL了解了如何定義數據庫和數據表&#xff08;DDL&#xff09;&#xff0c;接下來我們開始開始深入其數據,對其數據進行訪問&#xff08;DAL&#xff09;、查詢DQL&#xff08;&#xff09;和操作(DML)等。 通過DML語句操作管理數據庫數據 DML (數據操作語言) …

一文搞定 FastAPI 路徑參數

路徑參數定義 路徑操作裝飾器中對應的值就是路徑參數,比如: from fastapi import FastAPI app = FastAPI()@app.get("/hello/{name}") def say_hello(name: str):return {

突破編程_C++_STL教程( list 的基礎知識)

1 std::list 概述 std::list 是 C 標準庫中的一個雙向鏈表容器。它支持在容器的任何位置進行常數時間的插入和刪除操作&#xff0c;但不支持快速隨機訪問。與 std::vector 或 std::deque 這樣的連續存儲容器相比&#xff0c;std::list 在插入和刪除元素時不需要移動其他元素&a…

計算機網絡之傳輸層 + 應用層

.1 UDP與TCP IP中的檢驗和只檢驗IP數據報的首部, 但UDP的檢驗和檢驗 偽首部 首部 數據TCP的交互單位是數據塊, 但仍說TCP是面向字節流的, 因為TCP僅把應用層傳下來的數據看成無結構的字節流, 根據當時的網絡環境組裝成大小不一的報文段.10秒內有1秒用于發送端發送數據, 信道…

【Python】進階學習:pandas--groupby()用法詳解

&#x1f4ca;【Python】進階學習&#xff1a;pandas–groupby()用法詳解 &#x1f308; 個人主頁&#xff1a;高斯小哥 &#x1f525; 高質量專欄&#xff1a;Matplotlib之旅&#xff1a;零基礎精通數據可視化、Python基礎【高質量合集】、PyTorch零基礎入門教程&#x1f448;…

Python算法100例-3.5 親密數

1.問題描述2.問題分析3.算法設計4.確定程序框架5.完整的程序6.問題拓展 1&#xff0e;問題描述 如果整數A的全部因子&#xff08;包括1&#xff0c;不包括A本身&#xff09;之和等于B&#xff0c;且整數B的全部因子&#xff08;包括1&#xff0c;不包括B本身&#xff09;之和…

中國電子學會2020年6月份青少年軟件編程Sc ratch圖形化等級考試試卷四級真題。

第 1 題 【 單選題 】 1.執行下面程序&#xff0c;輸入4和7后&#xff0c;角色說出的內容是&#xff1f; A&#xff1a;4&#xff0c;7 B&#xff1a;7&#xff0c;7 C&#xff1a;7&#xff0c;4 D&#xff1a;4&#xff0c;4 2.執行下面程序&#xff0c;輸出是&#xff…

Oracle自帶的網絡工具(計算傳輸redo需要的帶寬,使用STATSPACK,計算redo壓縮率,db_ultra_safe)

--根據primary database redo產生的速率,計算傳輸redo需要的帶寬. 除去tcp/ip網絡其余30%的開銷,計算需要的帶寬公式: 需求帶寬((每秒產生redo的速率峰值/0.75)*8)/1,000,000帶寬(Mbps) --可以通過去多次業務高峰期的Statspack/AWR獲取每秒產生redo的速率峰值,也可以通過查詢視…

post請求體內容無法重復獲取

post請求體內容無法重復獲取 為什么會無法重復讀取呢&#xff1f; 以tomcat為例&#xff0c;在進行請求體讀取時實際底層調用的是org.apache.catalina.connector.Request的getInputStream()方法&#xff0c;而該方法返回的是CoyoteInputStream輸入流 public ServletInputStream…

CVE-2016-5195 復現記錄

文章目錄 poc前置知識頁表與缺頁異常/proc/self/mem的寫入流程madvise 漏洞點修復 Dirty COW臟牛漏洞是一個非常有名的Linux競爭條件漏洞&#xff0c;雖然早在2016年就已經被修復&#xff0c;但它依然影響著眾多古老版本的Linux發行版&#xff0c;如果需要了解Linux的COW&#…