JavaEE初階第十四期:解鎖多線程,從 “單車道” 到 “高速公路” 的編程升級(十二)

專欄:JavaEE初階起飛計劃

個人主頁:手握風云

目錄

一、JUC的常見類

1.1. Callable接口

1.2.?ReentrantLock?

1.3. 信號量Semaphore

1.4.?CountDownLatch

二、線程安全的集合類

2.1.?多線程環境使用 ArrayList?

2.2. 多線程環境使用哈希表


一、JUC的常見類

1.1. Callable接口

????????Callable是一個interface,類似于Runnable,把線程封裝了?個"返回值",方便程序員借助多線程的方式計算結果。

? ? ? ? 下面一個場景:創建線程計算1+2+3+4+……+100。

? ? ? ? 第一種寫法:通過Runnable的方案,需要借助成員變量sum,耦合性比較高。

public class Demo1 {private static int sum = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {int ret = 0;for (int i = 1; i <= 100; i++) {ret += i;}sum = ret;});t1.start();t1.join();System.out.println(sum);}
}

? ? ? ? 第二種寫法:使用Callable版本。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Demo2 {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable = new Callable<>(){@Overridepublic Integer call() throws Exception {int ret = 0;for (int i = 1; i <= 100; i++) {ret += i;}return ret;}};FutureTask<Integer> task = new FutureTask<Integer>(callable);Thread t = new Thread(task);t.start();System.out.println(task.get());}
}

? ? ? ? Callable帶有泛型參數,可以作為返回值計算結果。我們還需要重寫里面的call()方法來計算結果,再把callable利用FutureTask包裝一下,然后創建線程,將task傳入線程的構造方法中。在主線程中調用task.get(),能夠阻塞等待新線程計算完畢,并獲取到FutureTask中的結果。

????????對于FutureTask的理解,FutureTask是 Java 并發編程中異步任務與結果獲取的橋梁,通過封裝狀態管理、線程同步和異常處理,顯著簡化了異步編程模型。我們可以想象去吃麻辣燙,當餐點好后,后廚就開始做了,同時前臺會給你一張 "小票",這個小票就是FutureTask,后面我們可以隨時憑這張小票去查看自己的這份麻辣燙做出來了沒。

1.2.?ReentrantLock?

????????ReentrantLock也是可重入鎖,"Reentrant" 這個單詞的原意就是 "可重入"?。與synchronized定位類似,都是用來實現互斥效果,保證線程安全。

import java.util.concurrent.locks.ReentrantLock;public class Demo3 {private static int count = 0;public static void main(String[] args) throws InterruptedException {ReentrantLock locker = new ReentrantLock();Thread t1 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {locker.lock();count++;locker.unlock();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {locker.lock();count++;locker.unlock();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

????????ReentrantLock和synchronized 的區別:

  • synchronized 是一個關鍵字,是 JVM 內部實現的。ReentrantLock是標準庫的一個類, 在 JVM外實現的。
  • synchronized使用時不需要手動釋放鎖,ReentrantLock 使用時需要手動釋放,使用起來更靈活,但是也容易遺漏unlock。
  • synchronized 在申請鎖失敗時,會死等,ReentrantLock可以通過trylock的方式等待一段時間就放棄。
  • synchronized是非公平鎖,ReentrantLock默認是非公平鎖。可以通過構造方法傳入一個true 開啟公平鎖模式。
  • 更強大的喚醒機制,synchronized 是通過 Object 的 wait / notify 實現等待-喚醒. 每次喚醒的是一個隨機等待的線程。ReentrantLock 搭配 Condition 類實現等待-喚醒, 可以更精確控制喚醒某個指定的線程。

1.3. 信號量Semaphore

????????信號量,用來表示 "可用資源的個數",本質上就是一個計數器。我們申請資源(P操作),就會使計數器-1;釋放資源(V操作),就會使計數器+1。上述+1、-1的操作都是原子的。如果計數器為0,再去申請資源,就會造成阻塞。舉個例子,我們開車尋找停車場時,開進去,電子牌上的空閑車位就會-1,開出去,電子牌上的空閑車位就會+1。如果沒有空閑車位,就得停車等待或者尋找其他停車場。

import java.util.concurrent.Semaphore;public class Demo3 {public static void main(String[] args) throws InterruptedException {// 初始許可數為3,也就是“可用資源”的個數Semaphore semaphore = new Semaphore(3);semaphore.acquire();System.out.println("執行P操作");semaphore.acquire();System.out.println("執行P操作");semaphore.acquire();System.out.println("執行P操作");semaphore.release();}
}

? ? ? ? 上面初始值設為3,當我們申請4次之后,就會產生阻塞。

import java.util.concurrent.Semaphore;public class Demo3 {public static void main(String[] args) throws InterruptedException {// 初始許可數為3,也就是“可用資源”的個數Semaphore semaphore = new Semaphore(3);semaphore.acquire();System.out.println("執行P操作");semaphore.acquire();System.out.println("執行P操作");semaphore.acquire();System.out.println("執行P操作");semaphore.acquire();System.out.println("執行P操作");semaphore.release();}
}

? ? ? ? 信號量相當于鎖概念的延伸。換句話說,鎖也可以看作時初始值為1的特殊信號量。如果我們想要編寫的多線程代碼不允許使用鎖,也可以使用信號量保證線程安全。

import java.util.concurrent.Semaphore;public class Demo4 {private static int count = 0;public static void main(String[] args) throws InterruptedException {Semaphore semaphore = new Semaphore(1);// 創建一個線程t1,該線程執行的任務是:循環50_000次,每次執行時獲取semaphore的許可,然后count加1,最后釋放semaphore的許可Thread t1 = new Thread(() ->{for (int i = 0; i < 50_000; i++) {try {//  獲取semaphore的許可semaphore.acquire();// count加1count++;// 釋放semaphore的許可semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2 = new Thread(() ->{for (int i = 0; i < 50_000; i++) {try {semaphore.acquire();count++;semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

1.4.?CountDownLatch

? ? ? ? CountDownLatch是Java 并發包中的同步輔助工具,用于協調多個線程的執行順序,同時等待多個任務執行結束。比如在跑步?賽中,8個選?依次就位,哨聲響才同時出發;所有選?都通過終點,才能公布成績。

import java.util.concurrent.CountDownLatch;public class Demo5 {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(8);for (int i = 0; i < 8; i++) {int id = i;Thread t = new Thread(() -> {// 通過sleep模擬try {Thread.sleep(1_000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("線程" + id + "執行完畢");// 計數器減一,相當于一個運動員到達終點latch.countDown();});t.start();}// 主線程通過await()方法等待所有線程結束latch.await();System.out.println("所有任務執行完畢");}
}

? ? ? ? CountDownLatch通常用于一些特場景:在開發工作中,把一個大任務拆分成多個子任務,通過多線程并發執行,把所有任務完成之后才能進入下一階段。

二、線程安全的集合類

2.1.?多線程環境使用 ArrayList?

  • 自己使用同步機制 (synchronized 或者 ReentrantLock)?
  • Collections.synchronizedList(new ArrayList)。synchronizedList 是標準庫提供的一個基于 synchronized 進行線程同步的 List. synchronizedList 的關鍵操作上都帶有 synchronized?。

2.2. 多線程環境使用哈希表

????????HashMap 本身不是線程安全的,在多線程環境下可以使用Hashtable?或者ConcurrentHashMap。而Hashtable類似于Vector,在方法名上加上synchronized修飾,所以不推薦使用。

import java.util.Hashtable;public class Demo6 {public static void main(String[] args) {Hashtable<String, String> hashtable = new Hashtable<>();hashtable.put("111","aaa");hashtable.get("111");}
}
public synchronized V put(K key, V value) {……
}public synchronized V get(Object key) {……
}

? ? ? ? ConcurrentHashMap最大的調整就是針對鎖的粒度進行可優化。對于Hashtable來說,針對this加鎖,任何線程,只要操作這個哈希表都可能觸發鎖競爭。

? ? ? ? 兩個線程針對同一變量進行修改才會引發線程安全,所以針對哈希表來說,如果兩個線程的修改是在不同鏈表上,線程就是安全的。針對同一鏈表時,才引入阻塞。在ConcurrentHashMap中,每個鏈表都有一把鎖,稱為“鎖桶”。由于是不同的鎖對象,出發鎖競爭的概率就會降低。

? ? ? ? 在實際中,一個哈希表的桶的個數非常多,針對哈希表的操作,大部分是分布在不同桶上,觸發鎖競爭的概率可以忽略不計。

? ? ? ? ConcurrentHashMap擴容的時候,采取“化整為零”的方案。因為如果哈希表原來的元素很多,擴容會造成很大的開銷。為了保證線程安全,必須得加鎖,如果全部進行搬運,持有鎖的時間比較長,其他線程就無法正常使用哈希表了。

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

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

相關文章

什么是RabbitMQ?

什么是RabbitMQ? 一、什么是RabbitMQ? 二、Rabbitmq 的使用場景? 三、RabbitMQ基本概念 四、RabbitMQ的工作模式 1. **簡單隊列模式(Simple Queue)** 2. **工作隊列模式(Work Queue)** 3. **發布/訂閱模式(Publish/Subscribe)** 4. **路由模式(Routing)** 5. **主題…

DVWA靶場第一關--Brute force 新手入門必看!!!

文中涉及講解burp爆破模塊介紹可能不太準確&#xff0c;請大佬批評指正就dvwa靶場而言&#xff0c;兩個常見漏洞讓我有了新的認知第一個接觸的漏洞為弱口令漏洞&#xff0c;常見情況下&#xff0c;人們口中的弱口令可能為“姓名縮寫”“123456”“生日簡寫等”接觸了dvwa&#…

完美解決Docker pull時報錯:https://registry-1.docker.io/v2/

1、錯誤描述rootubuntu-database:/opt/dify/docker# docker compose up -d [] Running 9/9? api Error context canceled …

用 Python 批量處理 Excel:從重復值清洗到數據可視化

引言日常工作中&#xff0c;經常需要處理多份 Excel 表格&#xff1a;比如合并銷售數據、清洗重復的用戶信息&#xff0c;最后生成可視化圖表。手動操作不僅效率低&#xff0c;還容易出錯。這篇文章分享一套 Python 自動化流程&#xff0c;用pandas和matplotlib搞定從數據清洗到…

4.5 點云表達方式——圖

(一)定義與原理 圖4-5-1 點云圖結構

wordpress菜單調用的幾種常見形式

在WordPress主題開發里&#xff0c;“菜單”在前端頁面中常見的調用/輸出形式可以歸納為5種&#xff0c;按出現頻率從高到低列給你&#xff0c;并給出最簡代碼片段&#xff0c;方便直接復制粘貼。 標準菜單位置調用(99%場景) 后臺“外觀→菜單”里把菜單A指派到菜單位置prima…

linux中pthread_t 的值與top -Hp中線程id值的區別

linux中pthread_t 值與top -Hp中線程id值的區別 #include <stdio.h> #include <pthread.h> #include <thread>void thread_func() {printf("child thread id0x%x\n",pthread_self());while(1){ printf("hello world\n");} }int ma…

Idea集成Jenkins Control插件,在IDEA中觸發Jenkins中項目的構建

IDEA可以下一個這個插件 Jenkins Control&#xff0c;直接在idea中觸發測試環境項目的部署測試環境API-TOKEN&#xff1a;XXXXXXXXXXXXXXXX&#xff08;在jenkins的首頁 - 系統管理 - 管理用戶中獲取&#xff09;配置號后&#xff0c;測試連接&#xff0c;需要是成功的狀態&…

【ARM】CMSIS6 介紹

1、 簡介CMSIS是通用微控制器軟件接口標準(Common Microcontroller Software Interface Standard ) 的簡寫。CMSIS 包括API、軟件組件、工具及工作流程&#xff0c;主要用于簡化軟件重用、縮短開發人員學習曲線&#xff0c;加快項目構建和調試&#xff0c;從而使產品更快上市。…

【含文檔+PPT+源碼】基于SSM的旅游與自然保護平臺開發與實現

項目介紹 本課程演示的是一款&#xff1f;&#xff1f;&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 帶你從零開始部署運行本套系統 該項目附帶的源碼資料…

QT6 源,十章繪圖(2)畫刷 QBrush:刷子只涉及填充顏色,線型,填充圖片,以及變換矩陣這幾個屬性,附源代碼帶注釋。

&#xff08;1&#xff09;本類的繼承關系如下 &#xff1a;&#xff08;2&#xff09;本類是支持流運算的 &#xff1a;&#xff08;3&#xff09;本類的構造函數與運算符 operator 函數 &#xff1a;關于本類的構造函數&#xff0c;進行以下測試 &#xff1a;只修改畫刷的構…

安科瑞智慧能源管理系統在啤酒廠5MW分布式光伏防逆流控制實踐

項目信息 光伏裝機1MW&#xff0c;3個并網點&#xff0c;低壓接 入配電系統。 要求自發自用、余電不上網。解決方案 通過防逆流保護裝置&#xff0c;做到剛性控制&#xff0c; 實現并網柜快速切斷&#xff1b;通過防逆流管理系統&#xff0c;做到柔性調節&#xff0c; 實現光伏…

VUE-第二季-02

3.Vue組件化 3.1 什么是組件 (1) 傳統方式開發的應用 一個網頁通常包括三部分&#xff1a;結構&#xff08;HTML&#xff09;、樣式&#xff08;CSS&#xff09;、交互&#xff08;JavaScript&#xff09; 傳統應用存在的問題&#xff1a; ① 關系縱橫交織&#xff0c;復雜…

【OpenGL】LearnOpenGL學習筆記02 - 繪制三角形、矩形

上接: https://blog.csdn.net/weixin_44506615/article/details/149861824 完整代碼&#xff1a;https://gitee.com/Duo1J/learn-open-gl 一、渲染管線 在開始之前&#xff0c;我們先簡單了解一下圖形渲染管線 在渲染3D物體時&#xff0c;我們常用到的一種幾何結構為網格模型…

Mysql的事務是什么?

簡單來說&#xff0c;MySQL 實現事務的核心就像是給你的數據庫操作加了一套“保險和存檔”機制。它確保了你的操作要么全部成功&#xff0c;要么全部失敗&#xff0c;并且在面對多人同時操作、系統突然崩潰等情況時&#xff0c;數據依然可靠、準確。 為什么需要事務呢&#xff…

測試開發:Python+Django實現接口測試工具

【測試開發天花板】DjangoVuePyTest打造企業級自動化平臺&#xff5c;能寫進簡歷的硬核項目最近被幾個公司實習生整自閉了&#xff0c;沒有基礎&#xff0c;想學自動化又不知道怎么去學&#xff0c;沒有方向沒有頭緒&#xff0c;說白了其實就是學習過程中沒有成就感&#xff0c…

TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》

核心思想 這篇論文的核心思想是提出一種全新的、數據驅動的自主模糊聚類&#xff08;Autonomous Fuzzy Clustering, AFC&#xff09;算法。其核心創新在于&#xff0c;它巧妙地結合了模糊聚類的靈活性和基于中位數&#xff08;medoids&#xff09;聚類的可解釋性&#xff0c;并…

ELK是什么

ELK 是一個廣受歡迎的開源技術棧&#xff0c;用于實時采集、處理、存儲、搜索、分析和可視化海量的日志數據&#xff08;log&#xff09;和機器生成的數據&#xff08;machine data&#xff09;&#xff0c;尤其是在 IT 系統監控、應用故障排查、安全分析和業務智能等領域應用廣…

[硬件電路-123]:模擬電路 - 信號處理電路 - 常見的高速運放芯片、典型電路、電路實施注意事項

一、高速運放常見芯片型號及特性高速運放&#xff08;高速運算放大器&#xff09;通常指帶寬&#xff08;GBW&#xff09;超過10MHz、壓擺率&#xff08;SR&#xff09;高于10V/μs的器件&#xff0c;適用于視頻處理、通信系統、高速數據采集等場景。以下是典型芯片及其特性&am…

關于解決WinRiver項目動態XmlElement的序列化與反序列化的問題

關于解決WinRiver項目動態XmlElement的序列化與反序列化的問題 一、WinRiver項目流量匯總XML內容 1.1、索引可變,索引下 XmlElement 元素內容固定 1.2、如何將對象 BottomTrack 的動態內容序列化為 XML ? 1.3、如何將 XML 動態內容反序列化為對象 BottomTrack ? 二、XML 動態…