Java大師成長計劃之第10天:鎖與原子操作

📢 友情提示:

本文由銀河易創AI(https://ai.eaigx.com)平臺gpt-4o-mini模型輔助創作完成,旨在提供靈感參考與技術分享,文中關鍵數據、代碼與結論建議通過官方渠道驗證。

在多線程編程中,鎖與原子操作是保證線程安全、維護數據一致性的重要工具。在第10天的學習中,我們將深入探討Java中的鎖機制,特別是synchronized關鍵字及java.util.concurrent包中的一系列并發工具。理解這些工具和技術是成為Java并發編程大師的重要一步。

一、synchronized關鍵字

synchronized是Java中用于實現線程安全的一個關鍵字。它是Java內置的同步機制,能夠幫助開發者避免由于多線程并發執行導致的數據不一致和線程安全問題。本文將深入探討synchronized關鍵字的特性、使用方法以及在多線程環境中的應用。

1.1 synchronized的基本概念

在多線程編程中,多個線程可能同時訪問共享資源(如類的靜態變量、實例變量或其他對象),如果沒有適當的同步機制,就可能導致數據不一致或競態條件。synchronized提供了一種簡單而有效的方式來控制對共享資源的訪問。

1.1.1 線程安全

線程安全是指在多線程環境中,代碼的執行順序和結果不受線程執行順序影響的性質。使用synchronized關鍵字,能夠確保同一時刻只有一個線程可以執行被標記為synchronized的代碼塊或方法,從而實現線程安全。

1.2 使用synchronized的方式

synchronized關鍵字可以用于方法和代碼塊之上,具體可以分為以下兩種使用方式:

1.2.1 方法級別的synchronized

在方法頭部使用synchronized關鍵字,可以確保在調用此方法時,其他線程不能同時訪問該方法。synchronized可以用于實例方法和靜態方法。

實例方法鎖

當一個實例方法被synchronized修飾時,它鎖定的是當前對象的實例。這意味著同一個對象的所有synchronized實例方法在任意時刻只能有一個線程執行:

public synchronized void increment() {this.count++;
}
靜態方法鎖

synchronized用于靜態方法時,它鎖定的是類的Class對象,而不是某個具體的實例。這樣同一個類的所有synchronized靜態方法也會遵循相同的鎖定規則:

public static synchronized void staticIncrement() {// 靜態變量操作staticCount++;
}

1.2.2 代碼塊級別的synchronized

除了方法級別的鎖定,synchronized也可以用于代碼塊,它允許開發者更精確地控制鎖的范圍。一段代碼塊可以被synchronized修飾,只需指定一個鎖對象。

public void increment() {synchronized (this) { // 鎖定當前實例this.count++;}
}

在上面的示例中,只有獲取了當前對象的鎖的線程才能執行代碼塊中的操作,減少了鎖的持有時間,提高了程序的性能。

1.2.3 自定義鎖對象

使用synchronized時,開發者可以指定任何對象作為鎖對象。這種方式可以更加靈活,特別是在需要對特定資源施加鎖定時:

private final Object lock = new Object();public void increment() {synchronized (lock) { // 鎖定自定義對象this.count++;}
}

1.3 鎖的可重入性

在Java中,synchronized是可重入的。這意味著同一個線程可以多次獲取同一個鎖,而不會導致死鎖。例如:

public synchronized void methodA() {methodB(); // 線程可以再次獲取同一個對象的鎖
}public synchronized void methodB() {// ...
}

在上面的例子中,線程在調用methodA時獲得鎖,接著在methodA內部又調用了methodB,該線程依然能夠順利獲得鎖并執行。

1.4 鎖的公平性

synchronized關鍵字不支持公平性。也就是說,線程對于獲取鎖的順序是無序的,某個線程可能在其他線程之后獲取鎖,這種情況被稱作“鎖饑餓”。為了避免這種情況,可以考慮使用java.util.concurrent包中的鎖機制,如ReentrantLock,它可以指定公平性策略,確保線程按照請求鎖的順序進行獲取。

1.5 使用synchronized的注意事項

1.5.1 易產生死鎖

在不恰當的使用情況下,synchronized可能導致死鎖。例如,兩個線程分別持有兩個不同的鎖,并在等待對方釋放鎖:

public void lockA() {synchronized (lockA) {// 省略其他代碼...lockB(); // 試圖獲取lockB的鎖}
}public void lockB() {synchronized (lockB) {// 省略其他代碼...lockA(); // 試圖獲取lockA的鎖}
}

為了避免死鎖,開發者應盡量規避嵌套鎖,并保證所有鎖的請求順序一致。

1.5.2 性能開銷

由于synchronized會導致上下文切換和線程阻塞,因此它相對較低效。在高并發場景下,不必要的鎖競爭會增加系統開銷。務必合理使用synchronized,盡量縮小鎖的范圍或使用其他并發工具。

1.6 小結

synchronized關鍵字是Java多線程編程中不可或缺的工具,它提供了基本的同步機制以確保線程安全。理解它的使用方式和特點,對于開發安全和高效的多線程應用程序至關重要。通過合理使用synchronized,開發者可以有效地管理并發問題,提高程序的穩定性與性能。然而,在復雜的應用場景下,開發者有時需要借助更靈活的并發工具(如ReentrantLock、CountDownLatch等)來補充synchronized的不足。掌握這些同步機制,將為成為Java大師奠定基礎。

二、java.util.concurrent包中的鎖與并發工具

在Java中,java.util.concurrent包提供了一系列強大的并發工具和鎖機制,極大地增強了多線程編程的靈活性和效率。相比于傳統的synchronized關鍵字,這些工具不僅支持更復雜的并發控制,還提供了更好的性能和更多的功能。本文將深入探討?java.util.concurrent?包中的幾種主要鎖和并發工具。

2.1 ReentrantLock類

ReentrantLockjava.util.concurrent包中最常用的顯式鎖。它是可重入的,即同一個線程可以多次獲取同一個鎖。與synchronized相比,ReentrantLock提供了更多的功能和靈活性。

2.1.1 創建和使用

以下是ReentrantLock的基本用法:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Counter {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock(); // 獲取鎖try {count++;} finally {lock.unlock(); // 確保釋放鎖}}public int getCount() {return count;}
}

在上述代碼中,lock.lock()方法用于獲取鎖,lock.unlock()方法則確保在操作完成后釋放鎖,即使發生異常也能保證鎖的釋放,這樣避免了由于未釋放鎖而導致的死鎖風險。

2.1.2 公平鎖與非公平鎖

ReentrantLock允許在創建時指定是否為公平鎖。如果設置為公平鎖,線程將按照請求鎖的順序獲取鎖,這樣可以有效避免“線程饑餓”的情況。創建公平鎖的示例:

Lock fairLock = new ReentrantLock(true); // 創建公平鎖

默認情況下,ReentrantLock是非公平的,它允許線程在競爭鎖時優先獲得鎖,即使其他線程已經在等待。

2.1.3 嘗試鎖定

ReentrantLock還有一個重要特點是提供了嘗試獲取鎖的方法。這使得線程在無法獲取鎖時可以選擇繼續執行其他操作。例如:

if (lock.tryLock()) {try {// 執行需要鎖定的任務} finally {lock.unlock();}
} else {// 鎖不可用時的處理邏輯
}

采用tryLock()方法設計代碼,可以減少線程的阻塞,提高系統的響應能力。

2.2 ReadWriteLock

ReadWriteLock是另一種重要的鎖機制,可以提高讀多寫少的場景中的并發性能。它允許多個線程同時讀取共享數據,而寫操作則是獨占的,即同一時間只能有一個線程進行寫入操作。

2.2.1 使用ReadWriteLock

ReadWriteLock通過ReentrantReadWriteLock類實現,獲取讀鎖和寫鎖的方式如下:

import java.util.concurrent.locks.ReentrantReadWriteLock;public class Data {private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();private int data;public int readData() {rwLock.readLock().lock();try {return data; // 讀取操作} finally {rwLock.readLock().unlock(); // 確保釋放讀鎖}}public void writeData(int newData) {rwLock.writeLock().lock();try {data = newData; // 寫入操作} finally {rwLock.writeLock().unlock(); // 確保釋放寫鎖}}
}

在這個例子中,多個線程可以并行讀取數據,但在寫入數據時,必須獲取寫鎖,這保證了數據的完整性和一致性。

2.3 Condition接口

Condition接口是以Lock為基礎的,用于實現線程間的協調和通知機制。它提供了await()signal()等方法,允許線程在某些條件下等待和被喚醒。

2.3.1 結合Lock使用

首先,通過Lock創建Condition實例:

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

接著,線程可以在某個條件上等待:

lock.lock();
try {while (!conditionMet) {condition.await(); // 等待條件}// 處理邏輯
} finally {lock.unlock();
}

其他線程可以通知條件已經發生變化:

lock.lock();
try {// 更新條件condition.signal(); // 喚醒其他等待線程
} finally {lock.unlock();
}

通過結合LockCondition,開發者能夠更靈活地設計復雜的線程協作機制。

2.4 并發集合

java.util.concurrent包還提供了一系列強大的并發集合類,如ConcurrentHashMapCopyOnWriteArrayListBlockingQueue等,從而使得數據結構在線程安全方面更加靈活、簡便。

2.4.1 ConcurrentHashMap

ConcurrentHashMap是線程安全的哈希表,允許多個線程并發地讀取和寫入。與HashTable不同,它通過分段鎖的機制實現高效的并發操作,大大提高性能。

import java.util.concurrent.ConcurrentHashMap;ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("key1", "value1");
String value = map.get("key1");

2.4.2 CopyOnWriteArrayList

CopyOnWriteArrayList是一個線程安全的變種列表,它的特點是對讀取操作的支持非常優化。它適用于讀操作遠多于寫操作的場景,因為每次寫操作都會復制底層數組。

import java.util.concurrent.CopyOnWriteArrayList;CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
String value = list.get(0);

2.4.3 BlockingQueue

BlockingQueue是一種支持阻塞操作的隊列,適用于生產者-消費者模型。它提供了多種操作,如添加、獲取、查看隊列頭元素等,且支持阻塞和超時功能:

import java.util.concurrent.ArrayBlockingQueue;ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("item1"); // 阻塞直到空間可用
String value = queue.take(); // 阻塞直到有元素可用

2.5 Atomic變量

除了鎖和線程安全集合外,java.util.concurrent包還提供了一系列原子類(如AtomicIntegerAtomicBoolean等),用于簡化基本類型的線程安全操作。這些類內部使用CAS(Compare-And-Swap)機制可以實現高效的線程安全操作。

2.5.1 使用Atomic變量

import java.util.concurrent.atomic.AtomicInteger;AtomicInteger atomicCount = new AtomicInteger(0);
int count = atomicCount.incrementAndGet(); // 原子性地增加計數

通過使用原子類,開發者可以避免使用顯式鎖,提高性能,尤其在高并發場景下。

2.6 小結

java.util.concurrent包為Java開發者提供了豐富的并發工具和鎖機制,使得多線程編程變得更加靈活和高效。從ReentrantLockBlockingQueue再到原子變量,開發者可以針對不同的并發場景選擇合適的工具,以提高程序性能和維護性。理解這些工具的使用方法和適用場景,將極大地增強你的并發編程能力。在現代Java應用程序中,熟練掌握這些工具是成為高效開發者的重要一步。

三、小結

在本篇博文中,我們深入探討了Java多線程編程中鎖與原子操作的重要性。熟練掌握synchronized關鍵字、java.util.concurrent包中的工具以及原子類的使用對于編寫健壯、高效的并發代碼至關重要。雖然synchronized關鍵字提供了基本的鎖機制,但在處理復雜并發場景時,ReentrantLockReadWriteLock和原子類提供的靈活性和高效性將顯著提升程序的性能和可靠性。

在接下來的學習中,建議在實踐中不斷探索,并結合具體場景選擇合適的并發工具,使我們在多線程編程領域更加得心應手,邁向Java大師的目標。

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

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

相關文章

線性代數——行列式?

目錄 一、行列式的定義? 1-1、三階行列式練習 1-2、下面介紹下三角行列式、上三角行列式、對角行列式 ?編輯 二、行列式的性質 2-1、性質1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6 ?編輯 2-2、性質7 2- 3、拉普拉斯定理、克萊姆法則 三…

微軟推出數款Phi 4“開放式”人工智能模型

微軟周三推出了幾款新的“開放式”人工智能模型&#xff0c;其中功能最強大的模型至少在一個基準測試上可與 OpenAI 的 o3-mini 相媲美。所有新的授權模型——Phi 4 mini reasoning、Phi 4 reasoning 和 Phi 4 reasoning plus——都是“推理”模型&#xff0c;這意味著它們能夠…

VPN訪問SAP組服務器報登陸負載均衡錯誤88:無法連接到消息服務器(RC=9)

用戶反饋用SAPGUI接入SAP時報錯&#xff1a;登陸負載均衡錯誤88&#xff1a;無法連接到消息服務器(RC9) 經了解是通過VPN訪問&#xff0c;但VPN沒有放行ICMP訪問&#xff0c;導致不能PING通&#xff0c;不能確認是網絡問題還是什么問題。 解決方案&#xff1a; 1、VPN由原&am…

使用AI-01開發板和開源后端服務搭建整套小智服務系統

使用AI-01開發板和開源后端服務搭建整套小智服務系統 四博智聯的AI-01開發板&#xff0c;基于樂鑫ESP32-C2 專屬定制的離線語音模組&#xff0c;能夠完美的接入小智AI服務平臺&#xff0c;再使用開源后端服務&#xff0c;就能夠搭建一個完整的小智AI服務系統了。 下面是具體…

字節跳動在GitHub上有哪些開源項目

字節跳動&#xff08;ByteDance&#xff09;在GitHub上開源了許多項目&#xff0c;涵蓋前端、后端、云原生、AI、數據庫等多個領域。以下是一些典型項目及其簡介&#xff1a; 1. 前端 & 跨平臺開發 Hippy 倉庫: Tencent/Hippy&#xff08;注&#xff1a;Hippy 最初由騰訊開…

超長8分鐘Suno V4.5 – 支持一首歌多風格轉換啦~~~

f歷史文章 Suno AI API接入 - 將AI音樂接入到自己的產品中&#xff0c;支持120并發任務 AI音樂支持中文&#xff0c;實測效果&#xff0c;大家自己聽聽看嘍 2025年新年快樂&#xff0c;Viggle AI打開新年快樂 讓照片舞動起來&#xff0c;只要3分鐘就可以搞定了&#xff0c;…

vue3+ts項目 配置vue-router

安裝vue-router pnpm install vue-router配置 1.src/router/index.ts文件下的內容 import type { App } from vue import type { RouteRecordRaw } from vue-router import { createRouter, createWebHistory } from vue-router import remainingRouter from ./modules/remai…

如何利用dify 生成Fine?tune 需要的Alpaca 格式數據

如果你選擇llamafactory 格式進行微調&#xff0c;它只是格式是Alpaca格式&#xff0c;dify 的agent dsl 如下&#xff0c;你可以導入本地的dify 或者導入cloud 版本的&#xff1b;測試版本是0.1.5 app:description: 上傳文件&#xff0c;基于文件內容&#xff0c;使用 Silico…

C++開發指南

一、C++ 是什么? C++ 是一種強大、靈活、高性能的系統級編程語言,由 Bjarne Stroustrup 在 20 世紀 80 年代初開發,是 C 語言的超集。它既支持面向過程編程,也支持面向對象、泛型、函數式等現代范式。 C++ 被廣泛應用于: 系統軟件(如操作系統、編譯器)游戲開發(如 Un…

重測序關系矩陣構建方式匯總

樣本間親緣關系矩陣&#xff08;kinship matrix&#xff09;和同源性矩陣&#xff08;IBS matrix&#xff09;構建的方式 1. 可以使用plink的–make-rel計算個體之間的親緣關系&#xff08;強調個體之間的遺傳相似性&#xff09; /opt/software/plink --bfile vcf_bfile--mak…

docker 部署前、后端分離項目詳細步驟(從打包到部署)

在平常的開發工作中&#xff0c;一個項目經歷需求、開發、測試、上線等步驟。在開發測試完成后&#xff0c;我們需要部署測試環境、生產環境等&#xff0c;那么我們用 docker 方式應該怎么部署呢&#xff1f;前后端分離的項目又該如何部署呢&#xff1f;那么&#xff0c;今天我…

大語言模型理解一般需求到在專業領域中最大限度地發揮其效能的演變軌跡

在人工智能技術飛速發展的當下&#xff0c;大語言模型&#xff08;LLM&#xff09;憑借其強大的語言處理能力和廣泛的應用潛力&#xff0c;成為了各行業關注的焦點。從最初的文本生成、簡單問答&#xff0c;到如今在專業領域的深度應用&#xff0c;大語言模型與用戶的交互模式正…

mindyolo填坑

1、按照gitee上的文檔跑預測代碼&#xff0c;跑不通 更改&#xff1a; 將predict.py復制到跟目錄。如果是cpu&#xff08;本地測試比較常見&#xff09;&#xff0c;那么正確的命令行是&#xff1a; python predict.py --device_targetCPU --config ./configs/yolov7/yolov7.…

Python集合全解析:從基礎到高階應用實戰

一、集合核心特性與創建方法 1.1 集合的本質特征 Python集合&#xff08;Set&#xff09;是一種??無序且元素唯一??的容器類型&#xff0c;基于哈希表實現&#xff0c;具有以下核心特性&#xff1a; ??唯一性??&#xff1a;自動過濾重復元素??無序性??&#xff…

【javascript】競速游戲前端優化:高頻操作與并發請求的解決方案

文章目錄 前言一、性能痛點分析二、核心技術方案1.Web Worker2.Promise高級控制3.智能隊列系統4.游戲化節流設計 三、最佳實踐選擇 前言 在競速類網頁游戲中&#xff0c;玩家高頻點擊與服務器實時交互會引發兩大核心挑戰&#xff1a; 客戶端性能瓶頸&#xff1a;頻繁操作導致…

Linux操作系統系統編程:x86-64架構下的系統調用

在Linux操作系統里&#xff0c;系統編程如同精密儀器的核心部件&#xff0c;掌控著系統運行的關鍵。而 x86-64 架構下的系統調用&#xff0c;更是連接用戶空間程序與內核的關鍵橋梁。你可以把用戶空間的程序想象成一個個 “工匠”&#xff0c;它們有著各式各樣的需求&#xff0…

理解數據湖

目錄 一、數據湖的定義與相關概念 二、數據湖出現的背景 三、數據湖關鍵技術 (一)存儲技術

前端應用開發技術歷程的簡要概覽

前端應用開發技術詳解 一、萌芽期&#xff08;1990s - 2004&#xff09; 技術特征 HTML 3.2 / HTML 4.01 是主流版本。 樣式用 CSS1/CSS2&#xff0c;但大部分樣式寫在 <style> 標簽甚至行內。 動態效果主要通過 JavaScript 控制 DOM&#xff0c;兼容性極差。 代表事…

交換機配置DHCP

交換機配置DHCP 背景先關閉路由器的DHCPconsole口連接到交換機配置交換機 背景 路由器的dhcp分配IP地址變慢&#xff0c;怎么處理 先關閉路由器的DHCP 查看路由器中DHCP地址池范圍; 關閉路由器的DHCP console口連接到交換機 協議Serial端口COMX波特率9600流控無 配置交換機…

解決Flutter項目中Gradle構建Running Gradle task ‘assembleDebug‘卡頓問題的終極指南

解決Flutter項目中Gradle構建Running Gradle task ‘assembleDebug‘卡頓問題的終極指南 前言 在開發Flutter應用時,經常會遇到Gradle構建卡在Running Gradle task assembleDebug階段的問題。本文將分享如何通過配置華為云鏡像和使用自定義腳本下載依賴的方法解決這些問題。…