java 樂觀鎖的實現和注意細節

文章目錄

  • 1. 前言
    • 樂觀鎖 vs. 悲觀鎖:基本概念對比
    • 使用場景及優勢簡述
  • 2. 基于版本號的樂觀鎖實現
    • 代碼示例
    • 注意事項
  • 3. 基于CAS機制的樂觀鎖實現
    • 核心思想
    • 代碼示例
      • 關鍵點說明
  • 4. 框架中的樂觀鎖實踐
    • MyBatis中基于版本號的樂觀鎖實現
      • 示例代碼
    • JPA(Hibernate)中的樂觀鎖
      • @Version 注解關鍵點與底層原理
      • 示例代碼
  • 5. 樂觀鎖使用中的注意細節
    • 并發沖突后的重試機制與失敗處理
    • 事務管理中的注意事項
    • 數據持久化時的并發一致性保障
    • 適用場景的取舍:當沖突過于頻繁時的風險分析
  • 實際應用中的問題
    • 是否可以用狀態機(比如:待支付 支付中 支付完成 支付異常)作為版本號
    • mysql樂觀鎖是否一定需要和事務同時出現才有效果
    • 沒有事務支持使用版本號邏輯 mysql樂觀鎖會出現什么問題

1. 前言

在現代并發編程中,如何有效處理數據爭搶和共享資源的訪問是一項很關鍵的問題。常用的兩種策略是樂觀鎖和悲觀鎖,它們雖然目標相同——確保數據的一致性和完整性——但采用的方法卻截然不同。

樂觀鎖 vs. 悲觀鎖:基本概念對比

  • 悲觀鎖

    • 思想:對每次操作前都假設可能發生數據沖突,因此在操作時先加鎖,確保資源不會被其他線程/進程同時修改。
    • 特點:
      • 適用于寫操作較多、數據沖突較頻繁的場景。
      • 實現方式通常依賴數據庫鎖(如行鎖、表鎖)或使用Java中的synchronized關鍵字。
    • 類比:就像在辦公室會議室中安排發言,每個人在發言前都得先預定會議室,確保不會有人同時使用。
  • 樂觀鎖

    • 思想:假設數據在大部分情況下不會發生沖突,因此直接進行操作,在提交更新時再進行版本驗證(如基于版本號或CAS判斷)。
    • 特點:
      • 適用于讀取操作遠多于寫入操作,因為數據修改的沖突幾率較低。
      • 不需要在每次操作前對數據進行加鎖,性能一般更好,但在沖突時需要重試操作。
    • 類比:就像大家在共享一個白板上標注信息,盡管同時編輯的情況可能存在,但大多數人不會同時做出修改,當檢測到沖突時大家回頭進行調整。

使用場景及優勢簡述

  • 使用場景:

    • 數據庫場景:
      • 悲觀鎖更適用于那些寫操作頻繁、業務邏輯要求嚴格的場景,如銀行轉賬系統。
      • 樂觀鎖適合于讀操作較多、寫操作相對較少的場景,如商品庫存查看、博客評論系統。
    • 內存并發場景:
      • 悲觀鎖用在要求線程安全且數據操作沖突率高的情況,可能采用ReentrantLocksynchronized
      • 樂觀鎖通過CAS等機制保證數據修改的正確性,適合于低沖突或容錯性較好的系統設計。
  • 優勢比較:

    • 樂觀鎖:
      • 提升性能:避免頻繁加鎖和解鎖帶來的性能損耗。
      • 高度并發:在多數操作不沖突的情況下,多線程能高效執行。
    • 悲觀鎖:
      • 數據安全:即使高并發情況下,也能確保數據絕對不會出現臟讀或不一致的情況。
      • 實現簡單:邏輯上比較直觀,容易理解。

2. 基于版本號的樂觀鎖實現

在開發中,我們通常會在數據表中增加一個版本號字段(version)或者在內存中的共享對象設置一個版本屬性。工作流程大致如下:

  1. 讀取數據時,同時獲取當前版本號。
  2. 在更新數據時,帶上之前讀取到的版本號作為條件,執行類似下面的更新操作:
    • SQL 更新語句示例(假設數據表中有一個version字段):
      UPDATE product
      SET stock = ?, version = version + 1
      WHERE id = ? AND version = ?
      
    • 如果更新成功,說明在讀取到更新之間數據未被修改;如果沒有更新數據(影響行數為0),說明中途數據被別人修改過,通常程序會捕獲這種情況,再進行相應的重試或異常處理。

這種方式保證了在更新操作時,如果其他事務已經修改了數據(導致版本號發生變化),當前事務將無法繼續更新,避免數據沖突。

代碼示例

設計一個簡單的倉儲類,通過版本號檢查更新庫存信息:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;public class ProductRepository {private DataSource dataSource;// 構造函數注入數據源public ProductRepository(DataSource dataSource) {this.dataSource = dataSource;}/*** 獲取指定產品的當前版本號*/public int getCurrentVersion(int productId) throws SQLException {String selectSQL = "SELECT version FROM product WHERE id = ?";try (Connection conn = dataSource.getConnection();PreparedStatement ps = conn.prepareStatement(selectSQL)) {ps.setInt(1, productId);try (ResultSet rs = ps.executeQuery()) {if (rs.next()) {return rs.getInt("version");} else {throw new SQLException("Product with id " + productId + " not found");}}}}/*** 更新產品的庫存,并利用樂觀鎖實現數據一致性控制*/public boolean updateProductStock(int productId, int newStock, int currentVersion) throws SQLException {String updateSQL = "UPDATE product SET stock = ?, version = version + 1 WHERE id = ? AND version = ?";try (Connection conn = dataSource.getConnection();PreparedStatement ps = conn.prepareStatement(updateSQL)) {ps.setInt(1, newStock);ps.setInt(2, productId);ps.setInt(3, currentVersion);int affectedRows = ps.executeUpdate();return affectedRows > 0;}}
}

示例中,我們首先通過 getCurrentVersion 方法獲取當前產品的版本號,然后在更新庫存時帶上該版本號作為條件。如果有其它事務在更新時修改了該記錄(導致版本號已發生改變),則 updateProductStock 執行時不會更新任何記錄,返回的 affectedRows 為 0,從而達到樂觀鎖控制數據并發沖突的目的。

下面是一個使用上述方法的簡單示例:

public class Application {public static void main(String[] args) {// 注意:此處數據源的初始化邏輯需要根據具體環境配置DataSource dataSource = DataSourceFactory.getDataSource(); // 假設有一個工廠類提供 DataSourceProductRepository repository = new ProductRepository(dataSource);int productId = 1; // 假設操作id為1的產品try {// 讀取產品當前版本號int currentVersion = repository.getCurrentVersion(productId);// 嘗試更新庫存boolean success = repository.updateProductStock(productId, 100, currentVersion);if (success) {System.out.println("更新成功,庫存已調整,新版本號已同步。");} else {System.out.println("更新失敗,數據可能已被其他操作修改,請準備重試操作。");}} catch (SQLException e) {e.printStackTrace();}}
}

注意事項

  • 數據版本一致性問題
    要確保所有對該數據的更新操作都使用版本號作為條件,否則可能破壞數據的一致性。如果遺漏了版本號條件,則可能出現部分操作修改成功、部分操作失敗的情況,最終導致數據狀態不符合預期。

  • 高并發下可能出現的沖突處理
    在高并發環境下,多線程或多事務可能同時讀取相同的版本號并嘗試更新,只有一個線程能夠更新成功。一般需要在業務層面對失敗的更新進行重試、記錄日志或者返回給用戶友好的消息。重試機制需要注意避免死循環或長時間等待,確保系統對并發沖突有有效的容錯處理策略。

3. 基于CAS機制的樂觀鎖實現

核心思想

CAS是一種硬件級別的原子操作,在Java中常通過java.util.concurrent.atomic包來實現。CAS操作的基本步驟是:

  1. 讀取內存中的某個變量的當前值。
  2. 與預期值(舊值)進行比較。
  3. 如果內存中的值與預期值相等,則將該值更新為新值;否則,說明在比較期間該變量已被其他線程修改,更新操作失敗。

這種原子性操作通常被封裝在循環內,不斷重試直至更新成功。在Java中,示例如下:

import java.util.concurrent.atomic.AtomicInteger;public class OptimisticLockExample {// 初始化版本號為0private AtomicInteger version = new AtomicInteger(0);public boolean updateVersion() {int currentVersion = version.get();// 假設新版本號為舊值+1int newVersion = currentVersion + 1;// 嘗試CAS操作return version.compareAndSet(currentVersion, newVersion);}public static void main(String[] args) {OptimisticLockExample example = new OptimisticLockExample();if (example.updateVersion()) {System.out.println("更新成功,當前版本為:" + example.version.get());} else {System.out.println("更新失敗,需采取重試機制。");}}
}

在這個例子中:

  • 我們使用了AtomicInteger來存儲版本號,實現原子性更新。
  • 調用compareAndSet方法:它會比較當前的值與預期的值,若相同則更新為新值,返回true;否則返回false,表示其他線程在此期間已做了修改。

通過CAS算法,我們可以在無需加鎖的情況下實現對共享數據的安全更新,這正是樂觀鎖在高并發場景下能提高性能的關鍵點。

代碼示例

下面給出一個簡單的示例,演示如何使用AtomicInteger實現CAS機制來對一個共享變量做安全更新:

import java.util.concurrent.atomic.AtomicInteger;public class CASExample {// 使用AtomicInteger來管理共享變量private AtomicInteger counter = new AtomicInteger(0);/*** 利用CAS循環機制更新counter的值* @param newValue 期望設置的新值* @return true表示更新成功,false表示更新過程中遇到問題(在本示例中,永遠會重試直到成功)*/public boolean updateCounter(int newValue) {while (true) {// 1. 獲取當前值int currentValue = counter.get();// 2. 執行比較并嘗試更新if (counter.compareAndSet(currentValue, newValue)) {// 如果當前值與期望值一致,則更新成功并退出System.out.println("更新成功:" + currentValue + " -> " + newValue);return true;} else {// 輸出調試信息,說明競爭導致更新失敗、正在重試System.out.println("CAS更新失敗,當前值已變為:" + counter.get() + ",準備重試。");}// 可選:可以在此添加退避策略,避免長時間自旋帶來的CPU飆高問題}}public static void main(String[] args) {CASExample example = new CASExample();// 模擬多線程下的并發更新情況Thread t1 = new Thread(() -> {example.updateCounter(1);});Thread t2 = new Thread(() -> {example.updateCounter(2);});t1.start();t2.start();}
}

關鍵點說明

  • 依賴包

    • 本示例依賴于 java.util.concurrent.atomic.AtomicInteger,無需額外的第三方包。
  • CAS循環機制

    • 在 updateCounter 方法中,通過一個無限循環不斷嘗試調用 compareAndSet。當操作失敗(說明其他線程已經修改了該變量)時,會再次獲取最新值并重試。
  • 自旋鎖與性能問題

    • 如果多個線程競爭激烈,CAS循環可能會導致大量的自旋重試,進而消耗較多CPU資源。在實際生產環境中,可以加入退避策略(例如在每次失敗后休眠一段動態調整的時間),以減少自旋帶來的性能損耗。

4. 框架中的樂觀鎖實踐

在實際開發中,很多持久化框架都內置了樂觀鎖實現的支持,下面介紹 MyBatis 和 JPA(Hibernate)中的實踐方式。


MyBatis中基于版本號的樂觀鎖實現

MyBatis 通常通過在 Mapper XML 中編寫帶有版本號條件的更新語句來實現樂觀鎖。在使用時,需要注意以下配置點:

  1. 數據庫表需要定義一個版本號字段(如 version)。
  2. 實體類對應數據庫記錄時,需要映射該 version 字段。
  3. 編寫更新 SQL 時,應在 WHERE 條件中加入 version 字段的判斷,即:
    • 更新時要求數據庫記錄的版本號與傳入的版本一致,更新成功后版本號加一。
  4. 如果更新返回受影響行數為 0,則說明記錄可能被其他事務修改,需要做相應的處理,比如重試或告警。

示例代碼

假設有一個 Product 實體,其中包含 id、stock、version 等字段。下面是 MyBatis 的 Mapper XML 配置示例:

– ProductMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mapper.ProductMapper"><!-- 根據ID查詢產品(包含版本號) --><select id="selectProductById" resultType="com.example.entity.Product">SELECT id, stock, versionFROM productWHERE id = #{id}</select><!-- 基于版本號的樂觀鎖更新 --><update id="updateProductStock" parameterType="com.example.entity.Product">UPDATE productSET stock = #{stock},version = version + 1WHERE id = #{id} AND version = #{version}</update></mapper>

在 Java 中調用時,可以寫一個 Service 層方法:

package com.example.service;import com.example.entity.Product;
import com.example.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class ProductService {@Autowiredprivate ProductMapper productMapper;@Transactionalpublic boolean updateStock(int productId, int newStock) {// 查詢當前記錄Product product = productMapper.selectProductById(productId);if (product == null) {throw new RuntimeException("產品不存在");}// 設置新的庫存值product.setStock(newStock);// 執行更新;更新返回值為受影響行數int affectedRows = productMapper.updateProductStock(product);return affectedRows > 0;}
}

這樣在更新時,如果其它事務已經修改了記錄(導致版本號不一致),則本次更新不會影響到任何記錄,服務層可據此判斷是否需要重試或返回錯誤信息。


JPA(Hibernate)中的樂觀鎖

JPA 提供了內置的樂觀鎖支持,開發人員只需在實體中通過注解 @Version 標記一個版本字段即可。Hibernate 在底層自動通過 SQL’s UPDATE 的 WHERE 子句檢查版本號,從而實現樂觀鎖機制。

@Version 注解關鍵點與底層原理

  1. 定義版本號字段

    • 在實體類中添加一個字段,比如 Integer、Long 或 Timestamp 類型,并加上 @Version 注解。
    • 當實體被更新時,Hibernate 會在更新語句中加入類似 “WHERE id = ? AND version = ?” 的判斷,如果版本不匹配,則更新返回 0 行數據,進而拋出 OptimisticLockException 異常。
  2. 底層原理

    • 每次更新操作前,Hibernate 讀取實體當前的版本號。
    • 執行更新時,將版本號作為條件,如果數據庫記錄中的版本與傳入一致,則更新成功;同時 Hibernate 會自動將版本號遞增。
    • 如果更新失敗,說明數據版本與預期不符,通常會拋出異常,提示樂觀鎖沖突。

示例代碼

下面是一個簡單的 JPA 實體示例:

package com.example.entity;import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import javax.persistence.Table;@Entity
@Table(name = "product")
public class Product {@Idprivate Integer id;private Integer stock;// 使用@Version注解標記版本字段@Versionprivate Integer version;// getter和setter省略public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getStock() {return stock;}public void setStock(Integer stock) {this.stock = stock;}public Integer getVersion() {return version;}public void setVersion(Integer version) {this.version = version;}
}

在 Spring Data JPA 或純 JPA 中,只需正常調用 save 方法即可,底層會自動管理版本號更新:

package com.example.service;import com.example.entity.Product;
import com.example.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Transactionalpublic void updateProductStock(Integer productId, Integer newStock) {Product product = productRepository.findById(productId).orElseThrow(() -> new RuntimeException("產品不存在"));product.setStock(newStock);// 調用save方法時,Hibernate會生成:// UPDATE product SET stock = ?, version = version + 1 WHERE id = ? AND version = ?productRepository.save(product);}
}

如果在并發環境下存在版本沖突,Hibernate 會拋出 OptimisticLockException,這時可以捕獲異常,并進行相應的重試或錯誤提示處理。

5. 樂觀鎖使用中的注意細節

在使用樂觀鎖時,開發者需要注意多個細節以保障系統的數據一致性、性能和用戶體驗。下面對幾個關鍵點進行詳細說明:


并發沖突后的重試機制與失敗處理

  1. 重試機制設計:

    • 當樂觀鎖檢測到版本不匹配時,通常需要在業務層實現重試邏輯。重試機制可以是簡單的固定次數重試,也可以采用指數退避(Exponential Back-off)機制,來避免頻繁并發寫操作時的性能瓶頸。
    • 重試次數不應過多,否則可能對系統性能和響應時間產生負面影響;一般會定義一定的最大重試次數,當超過這個次數,應該認為當前操作失敗并反饋給用戶或上層調用者。
  2. 失敗處理:

    • 如果重試多次后仍不能成功更新數據,則應捕捉到樂觀鎖異常,并根據業務邏輯決定是否需要回滾、通知用戶或記錄日志用于后續分析。
    • 在一些業務場景中,可能允許部分更新失敗以確保系統能繼續運轉,此時就需要對失敗結果進行合理的補償或告警機制。

事務管理中的注意事項

  1. 事務邊界:

    • 樂觀鎖通常依托于事務機制來確保數據在一次完整操作中的一致性,因此務必保證更新操作在同一事務內完成。
    • 應確保查詢、業務邏輯判斷和更新操作處在同一事務內,避免在事務提交前數據已經被其他線程修改。
  2. 隔離級別:

    • 雖然樂觀鎖利用版本號機制避免并發沖突,但事務的隔離級別依然起到關鍵作用。例如,在讀已提交(Read Committed)或可重復讀(Repeatable Read)的級別下,能較好地配合樂觀鎖,而在更低的隔離級別下,可能會導致不可預期的問題。
    • 設計事務時要充分考慮并發沖突與數據臟讀之間的平衡,必要時調優隔離級別或明確設置事務傳播行為,確保數據正確更新。

數據持久化時的并發一致性保障

  1. 數據一致性策略:

    • 樂觀鎖依靠版本號確保操作前后數據的一致性。當版本號不匹配時,更新操作被拒絕,從而避免數據覆蓋、丟失等問題。
    • 在持久化層面,要確保版本字段正確映射到數據庫,并在數據更新時遞增版本號,這樣才能有效地防止并發更新沖突。
  2. 并發一致性保障:

    • 應該考慮到分布式環境中數據復制、緩存失效等可能影響一致性的問題,可能需要結合分布式事務或緩存失效策略一起使用。
    • 對于讀取操作,如果需要更高的一致性保證,可能需要配合臟檢查操作或在適當的場景中禁用緩存。

適用場景的取舍:當沖突過于頻繁時的風險分析

  1. 樂觀鎖的適用場景:

    • 適合讀操作多、寫操作少的場景,因為樂觀鎖并不像悲觀鎖那樣在數據訪問前就加鎖,而是在更新時檢查版本號。
    • 在用戶操作較分散、沖突概率較低的環境(例如電商系統中的庫存更新)尤為適用。
  2. 沖突過于頻繁的風險:

    • 如果并發寫操作非常頻繁,樂觀鎖會經常檢測到版本沖突,從而觸發大量重試或失敗處理,這會導致系統響應變慢、資源耗損(如CPU占用增高)以及用戶體驗下降。
    • 此時,需要評估是否采用悲觀鎖機制、數據分片或引入其他協調機制來降低沖突概率,或者通過調優重試策略和失敗處理方式來適應高并發場景。
  3. 風險取舍:

    • 當沖突頻繁發生時,系統應根據業務特點在一致性、可用性和響應速度之間做出權衡。一方面,嚴格的數據一致性是保證業務正確運行的前提;另一方面,過高的并發沖突率會導致系統瓶頸。
    • 此外,還可以考慮將部分寫操作改為冪等設計,利用消息隊列或事件驅動架構來緩解直接高并發寫入數據庫造成的沖突。

實際應用中的問題

是否可以用狀態機(比如:待支付 支付中 支付完成 支付異常)作為版本號

不建議使用狀態機中的業務狀態(如“待支付”、“支付中”、“支付完成”、“支付異常”)來充當樂觀鎖的版本號。原因主要如下:

  1. 分離關注點原則

    • 狀態機中的狀態主要描述業務流程和狀態轉變,而版本號主要用于并發控制和數據一致性驗證。混用兩者容易導致職責不清,降低代碼的可維護性和理解度。
  2. 單調性與可靠性

    • 樂觀鎖依賴版本號具有單調遞增或連續變化的特性,以便在每次更新時能夠準確檢測到數據是否在一段時間內被其他事務修改。業務狀態通常是離散且有限的,不具備嚴格的單調性,有可能出現多次轉換到同一狀態的情況,從而無法作為有效的版本控制標識。
  3. 易引入風險

    • 使用業務狀態作為版本號,在進行業務流程設計時可能會存在狀態合理性校驗和版本沖突檢測混在一起的問題。如果業務狀態發生錯誤(例如業務流程狀態轉換本身設計不當或出現異常),就可能誤判沖突,甚至引發數據更新錯誤。
  4. 異常處理和可擴展性

    • 樂觀鎖中的版本號通常是由數據庫或框架自動管理的,不容易人為干預。而業務狀態需要根據業務邏輯進行轉換,如果重試或錯誤處理邏輯和版本號機制混淆后,會使得系統異常處理更加復雜,并增加未來擴展或變更時出錯的風險。

mysql樂觀鎖是否一定需要和事務同時出現才有效果

樂觀鎖本質上是一種數據版本控制的機制,用于檢測并發更新時數據是否發生變化。它通常依賴于數據庫的原子更新操作,而事務正是保證這類更新操作原子性的一種手段。

  1. 如果沒有事務支持,每個更新操作可能無法在單一的、原子性的環境中完成,導致在多線程或多進程并發場景下數據狀態難以準確檢測和更新。一旦版本檢測和更新操作不是原子執行,其他并發操作可能會介入修改,從而破壞樂觀鎖的檢測機制。

  2. 在實際的 ORM(如JPA/Hibernate)框架中,樂觀鎖往往依賴于事務作為基本單元,只有在事務邊界內才能確保版本號檢查和更新操作的原子性,從而有效避免數據沖突。

沒有事務支持使用版本號邏輯 mysql樂觀鎖會出現什么問題

下面給出一個簡單的示例,說明如果沒有事務支持時如何導致樂觀鎖版本檢查失效,從而引發并發更新數據不一致的問題。假設有個訂單實體 Order,屬性中包含 version 字段用以進行樂觀鎖檢查,下面代碼模擬兩個線程并發對同一個訂單進行修改的情況。

【問題場景說明】

  1. 初始訂單數據:
    ? id = 1
    ? status = “待支付”
    ? version = 1

  2. 同時有兩個線程(線程A、線程B)同時查詢到該訂單(均獲得 version=1)。

  3. 兩個線程開始各自的業務處理:
    ? 線程A處理完業務后,檢查訂單版本為1,準備更新訂單狀態為"支付中",并將版本號更新為2。
    ? 線程B處理完業務后,同樣檢查訂單版本為1,準備更新訂單狀態為"支付完成",并將版本號更新為2。

  4. 如果沒有事務的支持,這兩個操作往往不在原子操作中完成,可能出現如下的 race condition:
    ? 線程A更新增加 version 后,線程B由于仍檢測到 version 為1(或由于兩個線程并發,互相干擾),導致兩次更新并發寫入,最壞情況,線程B覆蓋了線程A的更新,導致數據“臟寫”。

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

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

相關文章

河北對口計算機高考C#筆記(2026高考適用)---持續更新~~~~

C#筆記 C#發展史 1998年,C#發布第一個版本。2002年,visual studio開發環境推出C#的特點 1.語法簡潔,不允許直接操作內存,去掉了指針操作 2.徹底面向對象設計。 3.與Web緊密結合。 4.強大的安全機制,語法錯誤提示,引入垃圾回收器機制。 5.兼容性。 6.完善的錯誤,異常處理…

C# dll版本沖突解決方案

隨著項目功能逐漸增加&#xff0c;引入三方庫數量也會增多。不可避免遇到庫的間接引用dll版本沖突&#xff0c;如System.Memory.dll、System.Buffer.dll等。編譯會報警&#xff0c;運行可能偶發異常。 可使用ILMerge工具合并動態庫&#xff0c;將一個庫的多個dll合并為一個dll。…

深度解析:etcd 在 Milvus 向量數據庫中的關鍵作用

目錄 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量數據庫中的關鍵作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架構簡介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 實際工作流程示意 ?? 如果 etcd 出現問題會怎樣&am…

隨機訪問介質訪問控制:網絡中的“自由競爭”藝術

想象一場自由辯論賽——任何人隨時可以發言&#xff0c;但可能多人同時開口導致混亂。這正是計算機網絡中隨機訪問協議的核心挑戰&#xff1a;如何讓多個設備在共享信道中高效競爭&#xff1f;本文將深入解析五大隨機訪問技術及其智慧。 一、核心思想&#xff1a;自由競爭 沖突…

設計模式作業

package sdau;public class man {public static void main(String[] args) {show(new Cat()); // 以 Cat 對象調用 show 方法show(new Dog()); // 以 Dog 對象調用 show 方法Animal a new Cat(); // 向上轉型 a.eat(); // 調用的是 Cat 的 eatCat c (Cat)a…

Kaspa Wasm SDK

文章目錄 1. 簡要2. github地址 1. 簡要 kaspa wallet SDK&#xff0c;在官方WASM基礎上封裝了應用層的方法&#xff0c;簡便了WASM的初始化及調用。 核心功能包括如下&#xff1a; 賬戶地址生成及管理Kaspa Api 和 Kasplex Api的封裝kaspa結點RPC 封裝P2SH的各個場景script封…

ROS mapserver制作靜態地圖

ROS mapserver制作靜態地圖 靜態地圖構建 1、獲取一個PNG地圖&#xff0c;二值化 2、基于PNG地圖&#xff0c;生成PGM地圖&#xff0c;可以通過一些網站在線生成&#xff0c;例如Convertio 文件配置 1、將文件放置于/package/map路徑下。 2、編寫yaml文件&#xff0c;如下…

tree 樹組件大數據卡頓問題優化

問題背景 項目中有用到樹組件用來做文件目錄&#xff0c;但是由于這個樹組件的節點越來越多&#xff0c;導致頁面在滾動這個樹組件的時候瀏覽器就很容易卡死。這種問題基本上都是因為dom節點太多&#xff0c;導致的瀏覽器卡頓&#xff0c;這里很明顯就需要用到虛擬列表的技術&…

瀏覽器工作原理05 [#] 渲染流程(上):HTML、CSS和JavaScript是如何變成頁面的

引用 瀏覽器工作原理與實踐 一、提出問題 在上一篇文章中我們介紹了導航相關的流程&#xff0c;那導航被提交后又會怎么樣呢&#xff1f;就進入了渲染階段。這個階段很重要&#xff0c;了解其相關流程能讓你“看透”頁面是如何工作的&#xff0c;有了這些知識&#xff0c;你可…

DrissionPage爬蟲包實戰分享

一、爬蟲 1.1 爬蟲解釋 爬蟲簡單的說就是模擬人的瀏覽器行為&#xff0c;簡單的爬蟲是request請求網頁信息&#xff0c;然后對html數據進行解析得到自己需要的數據信息保存在本地。 1.2 爬蟲的思路 # 1.發送請求 # 2.獲取數據 # 3.解析數據 # 4.保存數據 1.3 爬蟲工具 Dris…

android 布局小知識點 隨記

1. 布局屬性的命名前綴規律 與父容器相關的前綴 layout_alignParent&#xff1a;相對于父容器的對齊方式。 例如&#xff1a;layout_alignParentTop"true"&#xff08;相對于父容器頂部對齊&#xff09;。layout_margin&#xff1a;與父容器或其他控件的邊距。 例如…

GeoDrive:基于三維幾何信息有精確動作控制的駕駛世界模型

25年5月來自北大、理想汽車和 UC Berkeley 的論文“GeoDrive: 3D Geometry-Informed Driving World Model with Precise Action Control”。 世界模型的最新進展徹底改變動態環境模擬&#xff0c;使系統能夠預見未來狀態并評估潛在行動。在自動駕駛中&#xff0c;這些功能可幫…

Java高頻面試之并發編程-25

hello啊&#xff0c;各位觀眾姥爺們&#xff01;&#xff01;&#xff01;本baby今天又來報道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面試官&#xff1a;CAS都有哪些問題&#xff1f;如何解決&#xff1f; CAS 的問題及解決方案 CAS&#xff08;Compare and Swap&#xff0…

從碳基羊駝到硅基LLaMA:開源大模型家族的生物隱喻與技術進化全景

在人工智能的廣袤版圖上&#xff0c;一場從生物學羊駝到數字智能體的奇妙轉變正在上演。Meta推出的LLaMA(Large Language Model Meta AI)系列模型&#xff0c;不僅名字源自美洲駝(llama)&#xff0c;更以其開源特性和強大性能&#xff0c;引領了開源大模型社區的“駝類大爆發”…

可下載舊版app屏蔽更新的app市場

軟件介紹 手機用久了&#xff0c;app越來越臃腫&#xff0c;老手機卡頓成常態。這里給大家推薦個改善老手機使用體驗的方法&#xff0c;還能幫我們卸載不需要的app。 手機現狀 如今的app不斷更新&#xff0c;看似在優化&#xff0c;實則內存占用越來越大&#xff0c;對手機性…

Python_day47

作業&#xff1a;對比不同卷積層熱圖可視化的結果 一、不同卷積層的特征特性 卷積層類型特征類型特征抽象程度對輸入的依賴程度低層卷積層&#xff08;如第 1 - 3 層&#xff09;邊緣、紋理、顏色、簡單形狀等基礎特征低高&#xff0c;直接與輸入像素關聯中層卷積層&#xff08…

比較數據遷移后MySQL數據庫和達夢數據庫中的表

設計一個MySQL數據庫和達夢數據庫的表數據比較的詳細程序流程&#xff0c;兩張表是相同的結構&#xff0c;都有整型主鍵id字段&#xff0c;需要每次從數據庫分批取得2000條數據&#xff0c;用于比較&#xff0c;比較操作的同時可以再取2000條數據&#xff0c;等上一次比較完成之…

GC1808高性能24位立體聲音頻ADC芯片解析

1. 芯片概述 GC1808是一款24位立體聲音頻模數轉換器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采樣率&#xff0c;集成Δ-Σ調制器、數字抗混疊濾波器和高通濾波器&#xff0c;適用于高保真音頻采集場景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…

Linux 文本比較與處理工具:comm、uniq、diff、patch、sort 全解析

在類 UNIX 操作系統&#xff0c;特別是 Linux 系統中&#xff0c;命令行提供了一整套強大的文本處理工具&#xff0c;這些工具對于文件差異對比、內容篩選、文本排序以及源代碼管理尤為重要。今天&#xff0c;我們將結合真實示例&#xff0c;深入介紹并實戰演示 comm、uniq、di…

6月6日day46打卡

通道注意力(SE注意力) 知識點回顧&#xff1a; 不同CNN層的特征圖&#xff1a;不同通道的特征圖什么是注意力&#xff1a;注意力家族&#xff0c;類似于動物園&#xff0c;都是不同的模塊&#xff0c;好不好試了才知道。通道注意力&#xff1a;模型的定義和插入的位置通道注意力…