鎖的藝術:深入淺出講解樂觀鎖與悲觀鎖

????????在多線程和分布式系統中,數據一致性是一個核心問題。鎖機制作為解決并發沖突的重要手段,被廣泛應用于各種場景。樂觀鎖悲觀鎖是兩種常見的鎖策略,它們在設計理念、實現方式和適用場景上各有特點。本文將深入探討樂觀鎖和悲觀鎖的原理、實現、優缺點以及具體的應用實例,并結合代碼進行詳細講解,幫助讀者更好地理解和應用這兩種鎖機制。

目錄

一、鎖的基本概念

二、悲觀鎖

(一)悲觀鎖的基本概念

(二)悲觀鎖的特點

(三)悲觀鎖的實現方式

1. 數據庫中的悲觀鎖

2. Java中的悲觀鎖

(四)悲觀鎖的優缺點

三、樂觀鎖

(一)樂觀鎖的基本概念

(二)樂觀鎖的特點

(三)樂觀鎖的實現方式

1. 基于版本號的樂觀鎖

2. 基于時間戳的樂觀鎖

(四)樂觀鎖的優缺點

四、樂觀鎖與悲觀鎖的對比

(一)鎖機制

(二)性能

(三)適用場景

五、總結


一、鎖的基本概念

????????在并發編程中,鎖是一種用于控制多個線程對共享資源訪問的機制。鎖的主要目的是確保在同一時間只有一個線程能夠訪問共享資源,從而避免數據競爭和不一致問題。鎖的實現方式多種多樣,但其核心思想是通過某種機制來限制對共享資源的并發訪問


二、悲觀鎖

(一)悲觀鎖的基本概念

? ? ? ? 悲觀鎖是一種基于“悲觀”假設的鎖機制。它認為在并發環境中,多個線程對共享資源的訪問很可能會發生沖突,因此在訪問共享資源之前,會先對資源進行加鎖。只有獲得鎖的線程才能訪問資源,其他線程必須等待鎖釋放后才能繼續執行。悲觀鎖的核心思想是“寧可錯殺一千,不可放過一個”,通過嚴格的鎖機制來保證數據的一致性。

(二)悲觀鎖的特點

  1. 強一致性:悲觀鎖通過加鎖機制嚴格限制對共享資源的并發訪問,能夠確保在任何時候只有一個線程能夠修改資源,從而保證數據的強一致性。
  2. 高安全性:由于悲觀鎖在訪問資源之前會先加鎖,因此可以有效避免數據競爭和并發沖突,適用于對數據一致性要求較高的場景。
  3. 性能瓶頸:悲觀鎖的加鎖和解鎖操作會增加系統開銷,尤其是在高并發場景下,鎖的爭用可能導致線程阻塞,降低系統的性能。
  4. 適用場景:悲觀鎖適用于寫操作較多、數據競爭激烈的場景,例如數據庫事務中的行鎖和表鎖。

(三)悲觀鎖的實現方式

? ? ? ?悲觀鎖可以通過多種方式實現,常見的有基于數據庫的鎖機制和基于Java同步原語的鎖機制。

1. 數據庫中的悲觀鎖

????????在數據庫中,悲觀鎖可以通過SELECT ... FOR UPDATE語句實現。該語句會在查詢數據時對數據行加鎖,其他事務必須等待鎖釋放后才能對該行數據進行操作。

-- 查詢并鎖定一行數據
SELECT * FROM users WHERE id = 1 FOR UPDATE;
  • FOR UPDATE:該子句的作用是鎖定查詢結果中的行,防止其他事務對該行數據進行修改。

????????在Java中,可以通過JDBC操作數據庫來實現悲觀鎖。以下是一個簡單的示例代碼:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class PessimisticLockExample {public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {// 獲取數據庫連接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");// 設置事務為非自動提交connection.setAutoCommit(false);// 查詢并鎖定一行數據String sql = "SELECT * FROM users WHERE id = ? FOR UPDATE";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, 1);resultSet = preparedStatement.executeQuery();if (resultSet.next()) {// 獲取鎖定的數據String name = resultSet.getString("name");System.out.println("Locked user: " + name);// 模擬業務邏輯處理Thread.sleep(5000);// 更新數據String updateSql = "UPDATE users SET name = ? WHERE id = ?";preparedStatement = connection.prepareStatement(updateSql);preparedStatement.setString(1, "New Name");preparedStatement.setInt(2, 1);preparedStatement.executeUpdate();// 提交事務connection.commit();}} catch (SQLException | InterruptedException e) {e.printStackTrace();try {// 回滾事務if (connection != null) {connection.rollback();}} catch (SQLException ex) {ex.printStackTrace();}} finally {// 關閉資源try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null) {preparedStatement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}}
}

代碼說明

  • 使用SELECT ... FOR UPDATE語句查詢并鎖定數據行。

  • 設置事務為非自動提交模式,確保在事務提交之前,其他事務無法對該行數據進行修改。

  • 在鎖定數據后,模擬業務邏輯處理(如Thread.sleep(5000)),然后更新數據并提交事務。

  • 如果發生異常,回滾事務并釋放資源。

2. Java中的悲觀鎖

????????在Java中,悲觀鎖可以通過java.util.concurrent.locks包中的Lock接口及其實現類(如ReentrantLock)來實現。ReentrantLock提供了比內置鎖(synchronized)更靈活的鎖操作,例如嘗試鎖定(tryLock)、設置超時時間(tryLock(long timeout, TimeUnit unit))等。

????????以下是一個使用ReentrantLock實現悲觀鎖的示例代碼:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private final Lock lock = new ReentrantLock();public void doSomething() {lock.lock(); // 加鎖try {// 模擬業務邏輯System.out.println("Thread " + Thread.currentThread().getName() + " is doing something.");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock(); // 釋放鎖}}public static void main(String[] args) {ReentrantLockExample example = new ReentrantLockExample();// 創建多個線程訪問共享資源Thread t1 = new Thread(example::doSomething, "Thread-1");Thread t2 = new Thread(example::doSomething, "Thread-2");t1.start();t2.start();}
}

代碼說明

  • 使用ReentrantLocklock()方法加鎖,unlock()方法釋放鎖。

  • try塊中執行業務邏輯,確保在異常情況下能夠通過finally塊釋放鎖。

  • 多個線程訪問共享資源時,只有獲得鎖的線程能夠執行doSomething方法,其他線程必須等待鎖釋放。

(四)悲觀鎖的優缺點

優點

  1. 數據一致性高:悲觀鎖通過嚴格的鎖機制確保數據的一致性,適用于對數據一致性要求較高的場景。
  2. 實現簡單:悲觀鎖的實現相對簡單,尤其是在數據庫層面,通過SELECT ... FOR UPDATE語句即可實現。

缺點

  1. 性能瓶頸:悲觀鎖的加鎖和解鎖操作會增加系統開銷,尤其是在高并發場景下,鎖的爭用可能導致線程阻塞,降低系統的性能。
  2. 資源利用率低:由于悲觀鎖限制了并發訪問,可能導致資源利用率較低,尤其是在讀操作較多的場景下。

三、樂觀鎖

(一)樂觀鎖的基本概念

????????樂觀鎖是一種基于“樂觀”假設的鎖機制。它認為在并發環境中,多個線程對共享資源的訪問發生沖突的概率較低,因此在訪問資源時不加鎖,而是通過其他機制(如版本號或時間戳)來檢測數據是否被其他線程修改。如果檢測到數據被修改,則放棄當前操作并重試。樂觀鎖的核心思想是“先做事,再檢查”,通過減少鎖的使用來提高系統性能。

(二)樂觀鎖的特點

  1. 高性能:樂觀鎖減少了鎖的使用,降低了鎖的開銷,適用于讀操作較多、寫操作較少的場景,能夠顯著提高系統的性能。
  2. 資源利用率高:樂觀鎖允許多個線程并發訪問共享資源,提高了資源的利用率。
  3. 實現復雜:樂觀鎖的實現相對復雜,需要通過版本號或時間戳等機制檢測數據是否被修改。
  4. 適用場景:樂觀鎖適用于讀操作較多、寫操作較少的場景,例如緩存系統、分布式系統中的數據一致性控制。

(三)樂觀鎖的實現方式

????????樂觀鎖可以通過版本號(Version Number)或時間戳(Timestamp)來實現。以下分別介紹這兩種實現方式。

1. 基于版本號的樂觀鎖

????????基于版本號的樂觀鎖通過為每個數據項添加一個版本號字段來實現。每次修改數據時,版本號加1。在更新數據時,會檢查版本號是否發生變化。如果版本號發生變化,說明數據被其他線程修改過,當前操作需要重試。以下是一個基于版本號的樂觀鎖的實現示例:

import java.util.concurrent.atomic.AtomicInteger;public class OptimisticLockExample {private int value; // 數據值private AtomicInteger version = new AtomicInteger(0); // 版本號public void updateValue(int newValue) {int currentVersion = version.get(); // 獲取當前版本號while (true) {// 檢查版本號是否發生變化if (version.compareAndSet(currentVersion, currentVersion + 1)) {// 如果版本號未發生變化,更新數據value = newValue;System.out.println("Updated value to " + newValue + " with version " + version.get());break;} else {// 如果版本號發生變化,重試currentVersion = version.get();System.out.println("Version changed, retrying...");}}}public static void main(String[] args) {OptimisticLockExample example = new OptimisticLockExample();// 創建多個線程更新數據Thread t1 = new Thread(() -> example.updateValue(10), "Thread-1");Thread t2 = new Thread(() -> example.updateValue(20), "Thread-2");t1.start();t2.start();}
}

代碼說明

  • 使用AtomicInteger來實現版本號的線程安全操作。

  • 在更新數據時,通過compareAndSet方法檢查版本號是否發生變化。如果版本號未發生變化,則更新數據并增加版本號;如果版本號發生變化,則重試。

  • 多個線程更新數據時,通過版本號機制避免沖突。

2. 基于時間戳的樂觀鎖

????????基于時間戳的樂觀鎖通過為每個數據項添加一個時間戳字段來實現。每次修改數據時,更新時間戳。在更新數據時,會檢查時間戳是否發生變化。如果時間戳發生變化,說明數據被其他線程修改過,當前操作需要重試。以下是一個基于時間戳的樂觀鎖的實現示例:

import java.util.concurrent.atomic.AtomicLong;public class OptimisticLockWithTimestamp {private int value; // 數據值private AtomicLong timestamp = new AtomicLong(System.currentTimeMillis()); // 時間戳public void updateValue(int newValue) {long currentTimestamp = timestamp.get(); // 獲取當前時間戳while (true) {// 檢查時間戳是否發生變化if (timestamp.compareAndSet(currentTimestamp, System.currentTimeMillis())) {// 如果時間戳未發生變化,更新數據value = newValue;System.out.println("Updated value to " + newValue + " with timestamp " + timestamp.get());break;} else {// 如果時間戳發生變化,重試currentTimestamp = timestamp.get();System.out.println("Timestamp changed, retrying...");}}}public static void main(String[] args) {OptimisticLockWithTimestamp example = new OptimisticLockWithTimestamp();// 創建多個線程更新數據Thread t1 = new Thread(() -> example.updateValue(10), "Thread-1");Thread t2 = new Thread(() -> example.updateValue(20), "Thread-2");t1.start();t2.start();}
}

代碼說明

  • 使用AtomicLong來實現時間戳的線程安全操作。

  • 在更新數據時,通過compareAndSet方法檢查時間戳是否發生變化。如果時間戳未發生變化,則更新數據并更新時間戳;如果時間戳發生變化,則重試。

  • 多個線程更新數據時,通過時間戳機制避免沖突。

(四)樂觀鎖的優缺點

優點

  1. 高性能:樂觀鎖減少了鎖的使用,降低了鎖的開銷,適用于讀操作較多、寫操作較少的場景,能夠顯著提高系統的性能。
  2. 資源利用率高:樂觀鎖允許多個線程并發訪問共享資源,提高了資源的利用率。
  3. 減少鎖競爭:樂觀鎖通過版本號或時間戳機制避免了鎖的競爭,減少了線程阻塞的可能性。

缺點

  1. 實現復雜:樂觀鎖的實現相對復雜,需要通過版本號或時間戳等機制來檢測數據是否被修改。
  2. 沖突重試機制:樂觀鎖在檢測到沖突時需要重試,可能會導致操作失敗或性能下降,尤其是在高并發寫操作較多的場景下。
  3. 適用場景有限:樂觀鎖適用于讀操作較多、寫操作較少的場景,對于寫操作較多的場景,其性能優勢可能不明顯。

四、樂觀鎖與悲觀鎖的對比

(一)鎖機制

  • 悲觀鎖:通過加鎖機制限制對共享資源的并發訪問,確保在同一時間只有一個線程能夠訪問共享資源。

  • 樂觀鎖:不加鎖,通過版本號或時間戳機制檢測數據是否被修改,如果檢測到沖突則重試。

(二)性能

  • 悲觀鎖:加鎖和解鎖操作會增加系統開銷,尤其是在高并發場景下,鎖的爭用可能導致線程阻塞,降低系統的性能。

  • 樂觀鎖:減少了鎖的使用,降低了鎖的開銷,適用于讀操作較多、寫操作較少的場景,能夠顯著提高系統的性能。

(三)適用場景

  • 悲觀鎖:適用于寫操作較多、數據競爭激烈的場景,例如數據庫事務中的行鎖和表鎖。

  • 樂觀鎖:適用于讀操作較多、寫操作較少的場景,例如緩存系統、分布式系統中的數據一致性控制。


五、總結

樂觀鎖悲觀鎖
核心思想假設沖突較少,先操作再檢查沖突,通過版本號或時間戳檢測數據是否被修改。假設沖突較多,通過加鎖機制限制對共享資源的并發訪問。
鎖機制不加鎖,通過版本號或時間戳檢測數據是否被修改。加鎖,通過鎖機制限制對共享資源的并發訪問。
性能讀操作多、寫操作少時性能高,減少鎖的開銷。寫操作多時性能可能受限,鎖的爭用可能導致線程阻塞。
資源利用率允許多個線程并發訪問,資源利用率高。同一時間只有一個線程能訪問資源,資源利用率低。
實現復雜度實現相對復雜,需要版本號或時間戳機制。實現相對簡單,直接通過鎖機制實現。
適用場景讀操作多、寫操作少的場景,如緩存系統、分布式系統中的數據一致性控制。寫操作多、數據競爭激烈的場景,如數據庫事務中的行鎖和表鎖。
沖突處理發現沖突時重試操作。通過鎖機制避免沖突,其他線程等待鎖釋放。
數據一致性數據一致性依賴于重試機制,可能需要多次嘗試。數據一致性高,通過鎖機制嚴格保證。
并發能力并發能力強,允許多個線程同時讀取。并發能力弱,同一時間只有一個線程能操作。
適用語言/框架Java中可通過Atomic類實現版本號機制;數據庫中可通過版本號字段實現。Java中可通過synchronizedReentrantLock實現;數據庫中可通過FOR UPDATE實現。
優點性能高、資源利用率高、減少鎖競爭。數據一致性高、實現簡單、安全性高。
缺點實現復雜、沖突時需要重試、適用場景有限。性能瓶頸、資源利用率低、鎖競爭可能導致線程阻塞。

????????樂觀鎖和悲觀鎖是兩種常見的鎖機制,它們在設計理念、實現方式和適用場景上各有特點。悲觀鎖通過加鎖機制嚴格限制對共享資源的并發訪問,能夠確保數據的一致性,但可能會導致性能瓶頸。樂觀鎖通過版本號或時間戳機制檢測數據是否被修改,減少了鎖的使用,提高了系統的性能,但實現相對復雜,且在高并發寫操作較多的場景下可能不適用。

????????在實際應用中,選擇樂觀鎖還是悲觀鎖需要根據具體的業務場景和性能需求來決定。對于寫操作較多、數據競爭激烈的場景,悲觀鎖可能是更好的選擇;而對于讀操作較多、寫操作較少的場景,樂觀鎖則能夠顯著提高系統的性能。

通過本文的介紹,讀者可以更好地理解樂觀鎖和悲觀鎖的原理、實現和應用,從而在實際開發中合理選擇鎖機制,優化系統的性能和可靠性。

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

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

相關文章

Jinja2深度解析與應用指南

1. 概念與用途 1.1 核心概念 Jinja2是Python生態中功能強大的模板引擎,采用邏輯與表現分離的設計思想: 模板:包含靜態內容和動態占位符的文本文件(.j2后綴)渲染:將模板與數據結合生成最終文本的過程上下…

Ubuntu20.04中 Redis 的安裝和配置

Ubuntu20.04 中 Redis 的安裝和配置 Ubuntu 安裝 MySQL 及其配置 1. Redis 的安裝 更新系統包列表并安裝 Redis : # 更新包管理工具 sudo apt update# -y:自動確認所有提示(非交互式安裝) sudo apt install -y redis-server測…

Sklearn 機器學習 缺失值處理 填充數據列的缺失值

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】 ??使用 Scikit-learn 處理數據缺失值的完整指南 在機器學習項目中,數據缺失是不可避…

Unity中如何播放視頻

1.創建一個原始圖像并調整布局平鋪整個畫布 2.創建自定義紋理并調整自定義紋理大小 3.添加視頻播放組件 4.將準備好的視頻素材拖入到視頻剪輯中 5.將自定義紋理拖入到目標紋理中 6.將自定義紋理拖入到原始圖像的紋理中 最后運行游戲,即可播放視頻 總結:

Spring通用類型轉換的實現原理

Spring通用類型轉換的實現原理 設計思路實現邏輯ConversionService&#xff1a;類型轉換服務入口ConverterRegister&#xff1a;轉換器注冊接口GenericConversionService1. Map<ConvertiblePair, GenericConverter> converters2. canConvert() 與 convert()&#xff1a;服…

紅黑樹完全指南:為何工程都用它?原理、實現、場景、誤區全解析

紅黑樹完全指南&#xff1a;為何工程都用它&#xff1f;原理、實現、場景、誤區全解析 作者&#xff1a;星之辰 標簽&#xff1a;#紅黑樹 #平衡二叉查找樹 #工程實踐 #數據結構 #面試寶典 引子&#xff1a;工程師的“性能焦慮”與樹的進化史 你以為樹只是算法題里的配角&#…

阿里云 RDS mysql 5.7 怎么 添加白名單 并鏈接數據庫

阿里云 RDS mysql 5.7 怎么 添加白名單 并鏈接數據庫 最近幫朋友 完成一些運維工作 &#xff0c;這里記錄一下。 文章目錄 阿里云 RDS mysql 5.7 怎么 添加白名單 并鏈接數據庫最近幫朋友 完成一些運維工作 &#xff0c;這里記錄一下。 阿里云 RDS MySQL 5.7 添加白名單1. 登錄…

Psychopy音頻的使用

Psychopy音頻的使用 本文主要解決以下問題&#xff1a; 指定音頻引擎與設備&#xff1b;播放音頻文件 本文所使用的環境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音頻配置 Psychopy文檔鏈接為Sound - for audio playback — Psy…

分布式互斥算法

1. 概述&#xff1a;什么是分布式互斥 假設有兩個小孩想玩同一個玩具&#xff08;臨界資源&#xff09;&#xff0c;但玩具只有一個&#xff0c;必須保證一次只有一個人能夠玩。當一個小孩在玩時&#xff0c;另一個小孩只能原地等待&#xff0c;直到玩完才能輪到自己。這就是 …

[創業之路-410]:經濟學 - 國富論的核心思想和觀點,以及對創業者的啟發

一、國富論的核心思想和觀點 《國富論》全稱為《國民財富的性質和原因的研究》&#xff0c;由英國經濟學家亞當斯密于1776年出版&#xff0c;是經濟學領域的經典之作&#xff0c;其核心思想和觀點對現代經濟學的發展產生了深遠影響&#xff0c;具體如下&#xff1a; 勞動價值…

Tavily 技術詳解:為大模型提供實時搜索增強的利器

目錄 &#x1f680; Tavily 技術詳解&#xff1a;為大模型提供實時搜索增強的利器 &#x1f9e9; 為什么需要 Tavily&#xff1f; &#x1f50d; Tavily 是什么&#xff1f; 核心特性&#xff1a; &#x1f4e6; Tavily 在 RAG 架構中的位置 &#x1f9ea; 示例&#xff…

欣佰特科技亮相2025張江具身智能開發者大會:呈現人形機器人全鏈條解決方案

5月29日 &#xff0c;2025年張江具身智能開發者大會在上海落下帷幕。欣佰特科技作為專注人形機器人與具身智能領域的創新企業&#xff0c;攜一系列前沿產品與解決方案參展&#xff0c;與全球行業專家、企業共同探討技術落地路徑&#xff0c;展現其在具身智能領域的技術積累與場…

@Prometheus 監控-MySQL (Mysqld Exporter)

文章目錄 **Prometheus 監控 MySQL ****1. 目標****2. 環境準備****2.1 所需組件****2.2 權限要求** **3. 部署 mysqld_exporter****3.1 下載與安裝****3.2 創建配置文件****3.3 創建 Systemd 服務****3.4 驗證 Exporter** **4. 配置 Prometheus****4.1 添加 Job 到 prometheus…

MCP Resource模塊詳解

MCP Resource模塊詳解 摘要 MCP Resource模塊是模型上下文協議的核心組件&#xff0c;通過標準化URI接口為AI模型提供安全可控的只讀數據訪問能力。其核心設計包括數據隔離架構和客戶端驅動的訪問控制&#xff0c;支持文本/二進制編碼格式&#xff0c;適用于配置文件讀取、數據…

Docker 容器化基礎:鏡像、容器與倉庫的本質解析

Docker 概念與容器化技術 Docker 是一種容器化平臺&#xff0c;能夠將應用程序及其依賴項打包成一個容器&#xff0c;確保在任何環境中都能一致運行。容器化技術通過操作系統級別的虛擬化&#xff0c;為應用程序提供了一個獨立的運行環境。 容器化技術的核心優勢 一致性&…

解決SQL Server SQL語句性能問題(9)——SQL語句改寫(2)

9.4.3. update語句改寫 與Oracle類似,SQL Server中,update語句被用戶相關技術人員廣泛應用于現實日常工作中。但是,有些情況下,尤其是海量數據場景中,update語句也許會帶來性能方面的嚴重問題或極大隱患。因此,為了解決和消除update語句導致的性能問題或隱患,我們將需對…

Unity VR/MR開發-VR/開發SDK選型對比分析

視頻講解鏈接&#xff1a; 【XR馬斯維】Unity開發VR/MR用哪些SDK&#xff1f;【UnityVR/MR開發教程--入門】_嗶哩嗶哩_bilibili

Python 高效圖像幀提取與視頻編碼:實戰指南

Python 高效圖像幀提取與視頻編碼:實戰指南 在音視頻處理領域,圖像幀提取與視頻編碼是基礎但極具挑戰性的任務。Python 結合強大的第三方庫(如 OpenCV、FFmpeg、PyAV),可以高效處理視頻流,實現快速幀提取、壓縮編碼等關鍵功能。本文將深入介紹如何優化這些流程,提高處理…

java復習 05

我的天啊一天又要過去了&#xff0c;沒事的還有時間&#xff01;&#xff01;&#xff01; 不要焦慮不要焦慮&#xff0c;事實證明只要我認真地投入進去一切都還是來得及的&#xff0c;代碼多實操多復盤&#xff0c;別嘰嘰喳喳胡思亂想多多思考&#xff0c;有迷茫前害怕后的功…

《Go小技巧易錯點100例》第三十五篇

本期分享&#xff1a; 1.循環依賴導致棧溢出 2.無法捕獲子協程的panic 循環依賴導致棧溢出 在Go語言開發中&#xff0c;我們經常會遇到結構體之間需要相互引用的情況。當兩個結構體直接或間接地相互包含對方作為自己的字段時&#xff0c;就會形成循環依賴。 但是在Go語言中…