Java并發編程面試匯總

Java并發編程

  • 一、 基礎概念
    • 1. 進程與線程的區別是什么?
    • 2. 創建線程的幾種方式?
    • 3. 線程的生命周期(狀態)有哪些?
    • 4. 什么是守護線程(Daemon Thread)?
    • 5. 線程優先級(Priority)的作用及問題?
  • 二、線程安全與鎖機制
    • 1. 什么是線程安全?如何實現線程安全?
    • 2. synchronized 關鍵字的底層實現原理(對象頭、Monitor 機制)?
    • 3. volatile 關鍵字的作用和實現原理(內存屏障、可見性、禁止指令重排)?
    • 4. 什么是 CAS(Compare-And-Swap)?其優缺點?
    • 5. synchronized 和 ReentrantLock 的區別?
    • 6. 可重入鎖(ReentrantLock)的實現原理?
    • 7. 公平鎖與非公平鎖的區別?
    • 8. 什么是死鎖?如何避免或檢測死鎖?
    • 9. 偏向鎖、輕量級鎖、重量級鎖的升級過程?
    • 10. 鎖消除(Lock Elimination)和鎖粗化(Lock Coarsening)的原理?
  • 三、線程協作與通信
    • 1. `wait()`、`notify()`、`notifyAll()` 的使用場景和注意事項?
    • 2. `sleep()` 和 `wait()` 的區別?
    • 3. 如何實現線程間通信(如生產者-消費者模型)?
    • 4. `Condition` 接口的作用及與 `wait/notify` 的區別?
  • 四、并發工具類(JUC)
    • 1. `CountDownLatch`、`CyclicBarrier`、`Semaphore` 的使用場景和區別
      • **1.1 `CountDownLatch`**
      • **1.2 `CyclicBarrier`**
      • **1.3 `Semaphore`**
    • 2. `Exchanger` 的作用
    • 3. `Phaser` 的使用場景
    • 4. `Future` 和 `CompletableFuture` 的區別
    • 5. `StampedLock` 的優化點及使用場景
      • **優化點**
      • **使用場景**
  • 五、 線程池相關問題解析
    • 1. 線程池的核心參數及作用
    • 2. 線程池的工作流程(任務提交后的處理邏輯)
    • 3. 常見的線程池類型及其問題
    • 4. 線程池的拒絕策略
    • 5. 如何合理配置線程池參數
    • 6. 線程池中線程復用(Thread Reuse)的原理
    • 示例代碼
  • 六、 高級并發特性解析
    • 1. Java 內存模型(JMM)的核心概念
    • 2. 原子性、可見性、有序性及其保證方法
    • 3. 指令重排序及其避免方法
    • 4. ThreadLocal 的原理、使用場景及內存泄漏問題
    • 5. Fork/Join 框架與工作竊取機制
    • 示例代碼
  • 七、 并發容器解析
    • 1. ConcurrentHashMap 的實現原理(JDK7 vs JDK8)
    • 2. CopyOnWriteArrayList 的適用場景及優缺點
    • 3. BlockingQueue 的實現類及使用場景
    • 4. ConcurrentLinkedQueue 的無鎖實現原理
  • 八、 并發設計模式與實戰
    • 1. 生產者-消費者模式的實現方式
    • 2. 如何實現線程安全的單例模式
    • 3. 如何排查和解決死鎖問題
      • 排查方法
      • 解決措施
    • 4. 如何避免競態條件(Race Condition)
      • 加鎖同步
      • 原子操作
      • 不可變對象設計
      • 線程安全的集合
    • 5. 如何設計高并發場景下的計數器
      • 原子變量
      • LongAdder/LongAccumulator
      • 分段計數器
  • 九、底層原理與擴展
    • 1. Java 線程與操作系統線程的關系
    • 2. 什么是協程(Coroutine)?Java 中的虛擬線程(Loom 項目)
    • 3. 如何通過 jstack 分析線程狀態
    • 4. 什么是偽共享(False Sharing)?如何避免?
  • 十、其他擴展問題
    • 1. 如何實現異步編程(如 CompletableFuture、Reactive Streams)?
      • CompletableFuture
      • Reactive Streams
    • 2. 分布式鎖與單機鎖的區別
      • **單機鎖**
      • **分布式鎖**
    • 3. 無鎖編程(Lock-Free)的實現思路
      • **CAS(Compare-And-Swap)**
      • **樂觀鎖**
      • **無鎖數據結構**
    • 4. 高并發場景下常見的性能優化手段
      • **1. 減少鎖競爭**
      • **2. 線程池優化**
      • **3. 緩存機制**
      • **4. 異步 & 批量處理**
      • **5. 數據結構優化**

一、 基礎概念

1. 進程與線程的區別是什么?

進程與線程的主要區別如下:

  1. 定義
    • 進程(Process)是操作系統分配資源的基本單位。
    • 線程(Thread)是 CPU 調度的基本單位。
  2. 資源分配
    • 進程擁有獨立的內存空間和系統資源。
    • 線程共享進程的資源,如內存和文件句柄。
  3. 通信方式
    • 進程間通信(IPC)方式復雜,如管道、共享內存、消息隊列等。
    • 線程間通信更簡單,可通過共享變量直接通信。
  4. 開銷
    • 進程創建和切換開銷較大。
    • 線程切換成本較小,效率更高。
  5. 崩潰影響
    • 進程崩潰不會影響其他進程。
    • 線程崩潰可能影響整個進程。

2. 創建線程的幾種方式?

在 Java 中,創建線程主要有以下幾種方式:

  1. 繼承 Thread

    class MyThread extends Thread {public void run() {System.out.println("線程執行");}
    }public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
    }
    
  2. 實現 Runnable 接口

    class MyRunnable implements Runnable {public void run() {System.out.println("線程執行");}
    }public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
    }
    
  3. 使用 CallableFutureTask(可以返回值和拋出異常)

    import java.util.concurrent.*;class MyCallable implements Callable<String> {public String call() throws Exception {return "線程執行完成";}
    }public class Main {public static void main(String[] args) throws Exception {FutureTask<String> task = new FutureTask<>(new MyCallable());Thread thread = new Thread(task);thread.start();System.out.println(task.get());}
    }
    
  4. 使用線程池 ExecutorService

    import java.util.concurrent.*;public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(() -> System.out.println("線程執行"));executor.shutdown();}
    }
    

3. 線程的生命周期(狀態)有哪些?

線程的生命周期可分為以下幾種狀態:

  1. NEW(新建狀態):線程對象被創建,但未調用 start()
  2. RUNNABLE(就緒/運行狀態):調用 start() 方法后,等待 CPU 調度。
  3. BLOCKED(阻塞狀態):線程試圖獲取鎖但被阻塞。
  4. WAITING(無限等待狀態):線程調用 wait()join(),需顯式喚醒。
  5. TIMED_WAITING(計時等待狀態):線程調用 sleep(time)wait(time) 等方法。
  6. TERMINATED(終止狀態):線程執行完成或被異常終止。

4. 什么是守護線程(Daemon Thread)?

守護線程是后臺運行的線程,主要用于執行后臺任務,如垃圾回收。

  • 特點
    • 守護線程在所有非守護線程結束后,自動終止。
    • setDaemon(true) 方法可以設置線程為守護線程。

示例:

public class DaemonThreadExample {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("守護線程運行中...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});daemonThread.setDaemon(true);daemonThread.start();try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主線程結束");}
}

5. 線程優先級(Priority)的作用及問題?

  • Java 線程優先級范圍:1(最低)~ 10(最高)。
  • 線程默認優先級是 5
  • 使用 setPriority(int newPriority) 設置優先級。

示例:

Thread thread = new Thread(() -> System.out.println("線程運行"));
thread.setPriority(Thread.MAX_PRIORITY); // 設置最高優先級
thread.start();

問題

  1. 不一定生效:線程調度由操作系統決定,Java 只是建議。
  2. 可能導致線程饑餓:高優先級線程可能長時間占用 CPU,低優先級線程無法執行。
  3. 平臺相關:不同操作系統對線程優先級的實現可能不同。

二、線程安全與鎖機制

1. 什么是線程安全?如何實現線程安全?

線程安全指的是多個線程同時訪問共享數據時,不會導致數據的不一致性或錯誤。

實現線程安全的方法:

  1. synchronized 關鍵字:對方法或代碼塊加鎖,確保同一時間只有一個線程訪問。
  2. volatile 關鍵字:保證變量的可見性,防止指令重排序。
  3. ReentrantLock:可重入鎖,提供更靈活的鎖控制。
  4. CAS(Compare-And-Swap):無鎖并發編程,保證變量的原子性更新。
  5. 線程安全的集合類:如 ConcurrentHashMapCopyOnWriteArrayList
  6. ThreadLocal:為每個線程提供獨立變量,防止共享數據沖突。
  7. 原子操作類:如 AtomicIntegerAtomicReference

2. synchronized 關鍵字的底層實現原理(對象頭、Monitor 機制)?

synchronized 通過對象頭(Mark Word)中的鎖標志位和 Monitor 機制 實現。

  • 對象頭(Mark Word):存儲鎖信息,如偏向鎖、輕量級鎖、重量級鎖。
  • Monitor 機制:由操作系統的 互斥量(Mutex) 實現,線程競爭鎖時可能進入阻塞狀態。
  • 鎖升級過程
    1. 偏向鎖(Biased Locking)
    2. 輕量級鎖(Lightweight Locking)
    3. 重量級鎖(Heavyweight Locking)

示例:

synchronized (this) {System.out.println("同步代碼塊");
}

3. volatile 關鍵字的作用和實現原理(內存屏障、可見性、禁止指令重排)?

volatile 關鍵字作用:

  1. 保證可見性:修改后的值會立即刷新到主內存。
  2. 禁止指令重排序:防止 CPU 優化導致的順序問題。
  3. 不保證原子性:多個線程修改 volatile 變量仍可能導致競態條件。

底層實現:

  • 通過 內存屏障(Memory Barrier) 確保可見性。
  • 使用 MESI 緩存一致性協議 保證 CPU 緩存一致性。

示例:

private volatile boolean flag = true;

4. 什么是 CAS(Compare-And-Swap)?其優缺點?

CAS(比較并交換) 是一種無鎖并發機制,核心思想是:

  1. 讀取變量的當前值 V
  2. 如果 V 等于期望值 E,則更新為新值 N
  3. V 發生變化,則重新嘗試。

優點:

  • 無需加鎖,性能高。

缺點:

  • ABA 問題:可使用 AtomicStampedReference 解決。
  • 自旋消耗 CPU:長時間自旋可能降低性能。

示例:

AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.compareAndSet(0, 1);

5. synchronized 和 ReentrantLock 的區別?

對比項synchronizedReentrantLock
鎖的類型內置鎖顯式鎖
可重入性支持支持
公平鎖不支持支持
中斷響應不支持支持
條件變量不支持支持 Condition

6. 可重入鎖(ReentrantLock)的實現原理?

可重入鎖 允許同一線程多次獲取鎖。

  • ReentrantLock 通過 AQS(AbstractQueuedSynchronizer) 維護一個 state 變量,記錄獲取次數。
  • 線程釋放鎖時,state 遞減,直到 state == 0 時真正釋放鎖。

示例:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {System.out.println("執行任務");
} finally {lock.unlock();
}

7. 公平鎖與非公平鎖的區別?

  • 公平鎖:線程按順序獲取鎖,避免線程饑餓。
  • 非公平鎖:線程可以插隊獲取鎖,提高性能。

示例:

ReentrantLock lock = new ReentrantLock(true); // 公平鎖

8. 什么是死鎖?如何避免或檢測死鎖?

死鎖 是指多個線程相互等待對方釋放資源,導致程序無法繼續。

避免方法:

  1. 避免嵌套鎖
  2. 資源分配有序
  3. 超時機制
  4. 死鎖檢測工具(jstack、jconsole)

9. 偏向鎖、輕量級鎖、重量級鎖的升級過程?

鎖的升級流程:

  1. 無鎖狀態
  2. 偏向鎖:只有一個線程訪問。
  3. 輕量級鎖:多個線程競爭但無阻塞。
  4. 重量級鎖:多個線程競爭,阻塞等待。

10. 鎖消除(Lock Elimination)和鎖粗化(Lock Coarsening)的原理?

  • 鎖消除:JIT 編譯時,發現局部變量不逃逸,移除鎖。
  • 鎖粗化:多個連續加鎖的操作合并,減少鎖的頻繁釋放與獲取。

示例:

public void test() {StringBuilder sb = new StringBuilder(); // JIT 可能優化掉鎖sb.append("Hello");sb.append("World");
}

三、線程協作與通信

1. wait()notify()notifyAll() 的使用場景和注意事項?

  • 使用場景:
    wait()notify()notifyAll() 主要用于線程間的同步,適用于生產者-消費者模型或多個線程共享資源的情況。

    • wait(): 讓當前線程進入等待狀態,釋放鎖,讓其他線程可以獲取鎖并執行。
    • notify(): 喚醒一個wait() 狀態的線程,但不會立即釋放鎖,需等待當前線程執行完畢。
    • notifyAll(): 喚醒所有等待的線程,但只有一個線程能獲取鎖執行,其他線程仍需等待。
  • 注意事項:

    1. wait()notify()notifyAll() 必須在同步代碼塊或同步方法中使用,否則會拋 IllegalMonitorStateException
    2. 調用 wait() 方法后,線程會釋放鎖,進入等待隊列,直到被 notify()notifyAll() 喚醒。
    3. notify() 只是通知一個等待線程,并不會立即釋放鎖,必須等待持有鎖的線程執行完畢后才能釋放。

2. sleep()wait() 的區別?

對比項sleep()wait()
作用讓當前線程休眠一段時間讓當前線程等待,直到被 notify() 喚醒
釋放鎖不釋放鎖釋放鎖
使用位置可以在任何地方使用必須在同步代碼塊同步方法中使用
恢復方式時間到后自動恢復運行需要 notify()notifyAll() 喚醒
拋出異常InterruptedExceptionInterruptedException

3. 如何實現線程間通信(如生產者-消費者模型)?

示例:使用 wait()notify() 實現生產者-消費者模式

class SharedResource {private int data;private boolean available = false;public synchronized void produce(int value) {while (available) {try {wait(); // 生產者等待} catch (InterruptedException e) {e.printStackTrace();}}data = value;available = true;System.out.println("生產者生產: " + value);notify(); // 喚醒消費者}public synchronized int consume() {while (!available) {try {wait(); // 消費者等待} catch (InterruptedException e) {e.printStackTrace();}}available = false;System.out.println("消費者消費: " + data);notify(); // 喚醒生產者return data;}
}

4. Condition 接口的作用及與 wait/notify 的區別?

  • 作用:

    • Condition 提供了比 wait()notify() 更強大的線程間通信機制。
    • 允許多個等待隊列,可更精細地控制線程的喚醒。
  • 區別:
    | 對比項 | wait()/notify() | Condition |
    |------------|-----------------|------------|
    | 依賴的鎖 | 必須配合 synchronized 關鍵字使用 | 需要 Lock 對象 |
    | 等待方法 | wait() | await() |
    | 通知方法 | notify() / notifyAll() | signal() / signalAll() |
    | 多個等待隊列 | 只有一個等待隊列,notify() 可能會誤喚醒非目標線程 | 可以創建多個 Condition,更精準喚醒特定線程 |

  • 示例:使用 Condition 實現生產者-消費者模型

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class SharedResourceWithCondition {private int data;private boolean available = false;private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();public void produce(int value) {lock.lock();try {while (available) {condition.await(); // 生產者等待}data = value;available = true;System.out.println("生產者生產: " + value);condition.signal(); // 喚醒消費者} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public int consume() {lock.lock();try {while (!available) {condition.await(); // 消費者等待}available = false;System.out.println("消費者消費: " + data);condition.signal(); // 喚醒生產者return data;} catch (InterruptedException e) {e.printStackTrace();return -1;} finally {lock.unlock();}}
}

四、并發工具類(JUC)

1. CountDownLatchCyclicBarrierSemaphore 的使用場景和區別

1.1 CountDownLatch

  • 作用:用于 等待多個線程執行完畢后再繼續計數器只能減不能加
  • 使用場景
    • 任務分解:主線程等待多個子線程完成后再繼續。
    • 并發測試:多個線程同時執行某個任務,主線程等待所有線程完成。
    • 系統啟動依賴:等待多個資源加載完畢后再啟動服務。
import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(3);for (int i = 0; i < 3; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 完成任務");latch.countDown();}).start();}latch.await(); // 等待所有子線程執行完畢System.out.println("所有任務完成,繼續執行主線程");}
}

1.2 CyclicBarrier

  • 作用:用于 讓一組線程等待彼此到達某個同步點,并在到達后執行某個 回調任務
  • CountDownLatch 的區別
    • CountDownLatch 只能使用一次,CyclicBarrier重復使用
    • CyclicBarrier 允許在所有線程到達屏障時執行額外任務
  • 使用場景
    • 多人游戲:等待所有玩家加載完畢后開始游戲。
    • 并行計算:多線程分塊計算,待所有線程計算完成后合并結果。
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierExample {public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有線程到達屏障點"));for (int i = 0; i < 3; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 到達屏障");try {barrier.await();} catch (Exception e) {e.printStackTrace();}}).start();}}
}

1.3 Semaphore

  • 作用限流,用于控制并發線程數,類似停車場的車位管理。
  • 使用場景
    • 限制數據庫連接數
    • 控制接口并發訪問,防止系統崩潰。
    • 線程池限流,限制任務提交速率。
import java.util.concurrent.Semaphore;public class SemaphoreExample {public static void main(String[] args) {Semaphore semaphore = new Semaphore(2);for (int i = 0; i < 5; i++) {new Thread(() -> {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + " 獲取資源");Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " 釋放資源");semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}).start();}}
}

2. Exchanger 的作用

  • 作用兩個線程間的數據交換工具,用于在兩個線程之間安全地交換對象

  • 特點

    • 線程 A 調用 exchange() 方法后會阻塞,直到線程 B 也調用 exchange() 交換數據。
    • 適用于 生產者-消費者模型,當生產者產生數據,消費者等待數據時,Exchanger 可用作數據緩沖區
  • 使用場景

    • 數據處理:一個線程生產數據,另一個線程處理數據。
    • 大數據計算:并行計算任務的階段性交換。

3. Phaser 的使用場景

  • 作用可變并發任務同步工具,類似 CyclicBarrier,但支持 動態注冊/注銷線程

  • 區別

    • CyclicBarrier 需要指定固定數量的線程,Phaser 支持動態增減線程。
    • Phaser 適用于多階段任務,而 CyclicBarrier 適用于單次屏障
  • 使用場景

    • 分階段任務:如多輪競賽,每輪線程數不同。
    • 遞歸任務:動態管理并發線程的執行。

4. FutureCompletableFuture 的區別

對比項FutureCompletableFuture
異步能力只能獲取異步任務結果,不支持回調支持回調和流式操作,能更好地管理異步流程
阻塞獲取結果需要 get() 方法,可能會阻塞線程支持 thenApply() 等非阻塞操作
支持組合任務不支持多個 Future 組合thenCombine() 支持多個任務組合
異常處理只能手動 try-catch 處理exceptionally() 處理異常更方便
取消任務cancel() 方法cancel() 也可用
  • CompletableFuture 適用于更復雜的異步任務鏈,能提高代碼可讀性和效率。

5. StampedLock 的優化點及使用場景

優化點

  1. 支持三種模式

    • 寫鎖 (writeLock()):獨占鎖,類似 ReentrantReadWriteLock 的寫鎖。
    • 讀鎖 (readLock()):共享鎖,多個線程可同時讀。
    • 樂觀讀 (tryOptimisticRead()):不阻塞寫入,提高性能,適用于讀多寫少場景。
  2. 性能優勢

    • 避免讀鎖競爭:樂觀讀鎖不會阻塞寫操作,適用于高讀低寫的情況。
    • 降低鎖的升級開銷:先嘗試樂觀讀,再回退為悲觀鎖,減少鎖沖突。

使用場景

  • 緩存系統:大多數操作是讀取,寫入較少的情況,避免 ReentrantReadWriteLock 造成的讀鎖開銷。
  • 多線程計數器:多個線程同時讀計數值,少數線程寫入。
  • 金融交易系統:讀取賬戶余額時使用樂觀鎖,只有在余額變更時才獲取寫鎖。
import java.util.concurrent.locks.StampedLock;public class StampedLockExample {private int count = 0;private final StampedLock lock = new StampedLock();public int optimisticRead() {long stamp = lock.tryOptimisticRead();int current = count;if (!lock.validate(stamp)) {stamp = lock.readLock();try {current = count;} finally {lock.unlockRead(stamp);}}return current;}public void write(int value) {long stamp = lock.writeLock();try {count = value;} finally {lock.unlockWrite(stamp);}}
}

五、 線程池相關問題解析

1. 線程池的核心參數及作用

  • 核心線程數 (corePoolSize)
    指定了線程池中始終保持運行的最小線程數。當有新任務到達時,線程池會優先創建新線程直到達到核心線程數,之后任務才會進入隊列等待執行。

  • 最大線程數 (maximumPoolSize)
    表示線程池允許創建的最大線程數。當隊列已滿且核心線程都在忙碌時,線程池會創建新線程直至達到最大線程數。

  • 任務隊列 (workQueue)
    用于存放等待執行的任務。常用隊列類型有有界隊列(如 ArrayBlockingQueue)和無界隊列(如 LinkedBlockingQueue)。隊列的選擇會影響任務調度的策略和系統資源使用。

  • 線程空閑時間 (keepAliveTime)
    當線程數超過核心線程數時,多余線程在空閑狀態下等待新任務的最長時間,超時后這些線程會被終止,以節省資源。

  • 線程工廠 (threadFactory)
    用于創建新線程,可以通過自定義線程工廠設置線程名稱、優先級、守護狀態等,從而便于線程管理和調試。

  • 拒絕策略 (rejectedExecutionHandler)
    當線程池飽和(即線程數已達最大值且任務隊列也滿)時,對新提交任務的處理策略,如拋異常、調用者運行、丟棄任務或丟棄隊列中最老任務等。

2. 線程池的工作流程(任務提交后的處理邏輯)

  1. 任務提交
    當調用 execute()submit() 方法提交任務時,線程池首先判斷當前線程數是否小于核心線程數。

  2. 創建核心線程
    如果當前線程數小于核心線程數,則立即創建新線程執行任務,而不是將任務放入隊列。

  3. 任務入隊
    當核心線程數已滿,新的任務將被放入任務隊列中等待執行。

  4. 創建非核心線程
    如果任務隊列已滿,并且當前線程數小于最大線程數,則線程池會創建新線程來處理額外的任務。

  5. 拒絕策略觸發
    當任務隊列已滿且線程數已經達到最大線程數時,線程池根據配置的拒絕策略處理新提交的任務。

  6. 線程復用與銷毀
    完成任務后,線程不會立即銷毀,而是進入等待狀態以便復用。當線程超過核心線程數且長時間空閑,則會被回收。

3. 常見的線程池類型及其問題

  • FixedThreadPool

    • 特點:固定線程數,不會動態增減。
    • 問題:若任務執行緩慢或任務積壓,可能導致隊列中任務長時間等待,無法利用資源動態擴展。
  • CachedThreadPool

    • 特點:根據任務需要動態創建線程,線程空閑時會被回收,適用于任務執行時間較短的場景。
    • 問題:在任務激增時可能會創建大量線程,導致系統資源耗盡,甚至引發性能問題。
  • SingleThreadExecutor

    • 特點:單線程順序執行所有任務,適用于需要保證任務順序的場景。
    • 問題:單線程可能成為性能瓶頸,且任務過多時容易造成任務堆積。

4. 線程池的拒絕策略

  • AbortPolicy (默認策略)
    當任務無法執行時,直接拋出 RejectedExecutionException 異常,中斷任務提交流程。

  • CallerRunsPolicy
    由任務提交者所在的線程執行該任務,從而降低新任務的提交速率,緩解線程池壓力。

  • DiscardPolicy
    直接丟棄新提交的任務,不會拋出異常,但可能導致部分任務未被執行。

  • DiscardOldestPolicy
    丟棄任務隊列中等待最久的任務,然后嘗試提交當前任務,這樣可以為新的任務騰出空間。

5. 如何合理配置線程池參數

  • 根據任務性質配置線程數

    • CPU密集型任務:通常將線程數設置為 CPU 核心數或略微超出。
    • IO密集型任務:線程數可以設置為 CPU 核心數的多倍,因為等待時間較長。
  • 任務隊列的選擇
    根據任務特性選擇合適的隊列類型和容量。無界隊列雖能避免拒絕任務,但可能導致任務堆積;有界隊列則能限制任務數量,但在高負載時容易觸發拒絕策略。

  • 合理設置 keepAliveTime
    防止非核心線程在任務較少時占用系統資源,確保線程在空閑超時后被回收。

  • 拒絕策略的選取
    根據系統對任務丟失或延遲的容忍度選擇合適的拒絕策略,保障系統穩定性。

  • 動態調整策略
    根據實際運行情況,監控任務執行情況和系統資源使用情況,動態調整線程池參數以達到最佳性能。

6. 線程池中線程復用(Thread Reuse)的原理

  • 預先創建與等待
    線程池在初始化或任務提交時創建一定數量的核心線程,這些線程在完成任務后不會被銷毀,而是進入等待狀態,以便立即處理后續任務。

  • 任務隊列
    線程通過不斷從任務隊列中取任務來執行,實現線程的重復利用,避免頻繁創建和銷毀線程帶來的開銷。

  • KeepAlive 機制
    對于非核心線程,在任務執行完畢后,如果在指定的空閑時間內沒有新任務到達,則會被回收。這樣既能保證高負載時的擴展能力,也能在低負載時節省資源。

示例代碼

下面是一個簡單的 Java 示例,展示如何使用線程池提交任務。注意,Java 代碼已做適當轉義:

// 示例:使用線程池提交任務的簡單代碼
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 創建一個固定大小的線程池,核心線程數和最大線程數都為4ExecutorService executor = Executors.newFixedThreadPool(4);for (int i = 0; i < 10; i++) {executor.submit(new Runnable() {@Overridepublic void run() {System.out.println("執行任務 - " + Thread.currentThread().getName());}});}// 關閉線程池,等待所有任務執行完畢后退出executor.shutdown();}
}

六、 高級并發特性解析

1. Java 內存模型(JMM)的核心概念

  • 主內存與工作內存
    每個線程都有自己的工作內存,用于保存共享變量的副本,而共享變量本身存儲在主內存中。線程對變量的所有操作都必須先在工作內存中進行,再同步到主內存,從而保證了數據的一致性和線程間的可見性。

  • happens-before 原則
    規定了操作之間的先后關系,確保一個操作的結果在另一個操作執行前是可見的。典型規則包括:

    • 程序順序規則:單線程中代碼按照順序執行。
    • 鎖規則:解鎖操作 happens-before 后續對同一鎖的加鎖操作。
    • volatile 規則:volatile 寫操作 happens-before 隨后的 volatile 讀操作。
    • 線程啟動規則:線程啟動前的操作 happens-before 線程內的所有操作。

2. 原子性、可見性、有序性及其保證方法

  • 原子性
    一個操作是不可分割的,要么全部執行,要么全部不執行。
    保證方法

    • 使用 synchronized 關鍵字或顯示鎖(如 ReentrantLock)來保證復合操作的原子性。
    • 利用 Java 的原子類(如 AtomicInteger)實現無鎖的原子操作。
  • 可見性
    確保當一個線程修改了共享變量,其他線程能夠及時看到這個修改。
    保證方法

    • 使用 volatile 關鍵字,確保變量的修改立即刷新到主內存。
    • 使用鎖(synchronizedLock)來保證操作的可見性。
  • 有序性
    保證程序中指令按照代碼順序執行(在單線程環境下成立)。
    保證方法

    • 使用 synchronizedvolatile 提供的內存屏障,防止指令重排序。
    • JMM 中的 happens-before 規則確保了操作的有序性。

3. 指令重排序及其避免方法

  • 指令重排序原理
    為了優化性能,編譯器和處理器可能會重新排序指令。雖然在單線程環境中不會改變程序的正確性,但在多線程環境中可能會導致數據不一致的問題。

  • 避免方法

    • 內存屏障
      利用內存屏障指令保證某些操作在執行順序上的嚴格順序,從而防止重排序問題。
    • volatile 關鍵字
      使用 volatile 修飾的變量能確保寫操作不會被重排序到讀操作之后,并保證了可見性。

4. ThreadLocal 的原理、使用場景及內存泄漏問題

  • 原理
    每個線程內部都有一個 ThreadLocalMap,其中存儲了 ThreadLocal 對象和對應的線程局部變量。這樣,每個線程都可以獨立訪問和修改自己的變量副本,而不會影響其他線程。

  • 使用場景

    • 需要線程隔離的變量,如用戶會話、數據庫連接等。
    • 避免在多線程環境中共享數據而導致的同步問題。
  • 內存泄漏問題
    當線程使用完 ThreadLocal 后,如果沒有調用 remove() 方法清理 ThreadLocalMap,可能會導致內存泄漏,特別是在使用線程池等長生命周期線程時。
    解決方法

    • 在任務執行結束后主動調用 ThreadLocal.remove() 清理數據。
    • 注意設計長生命周期線程中 ThreadLocal 的使用,避免不必要的數據駐留。

5. Fork/Join 框架與工作竊取機制

  • Fork/Join 框架
    是 Java 7 引入的一個并行計算框架,適用于將大任務拆分成多個小任務(Fork),并行執行后將結果合并(Join)。核心組件包括 ForkJoinPoolForkJoinTask 以及其子類 RecursiveTask(有返回值)和 RecursiveAction(無返回值)。

  • 工作竊取機制 (Work-Stealing)
    每個工作線程維護一個雙端隊列,當線程完成了自己隊列中的任務時,會嘗試從其他線程隊列的尾部“竊取”任務以保持高效的資源利用和負載均衡。

示例代碼

以下是一個使用 Fork/Join 框架計算數組求和的示例代碼,注意 Java 代碼中的特殊字符均已轉義:

// 示例:使用 Fork/Join 框架計算數組求和
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinSum extends RecursiveTask<Long> {private static final int THRESHOLD = 1000;private long[] arr;private int start;private int end;public ForkJoinSum(long[] arr, int start, int end) {this.arr = arr;this.start = start;this.end = end;}@Overrideprotected Long compute() {if (end - start <= THRESHOLD) {long sum = 0;for (int i = start; i < end; i++) {sum += arr[i];}return sum;} else {int mid = (start + end) / 2;ForkJoinSum leftTask = new ForkJoinSum(arr, start, mid);ForkJoinSum rightTask = new ForkJoinSum(arr, mid, end);leftTask.fork(); // 異步執行左邊任務long rightResult = rightTask.compute(); // 同步執行右邊任務long leftResult = leftTask.join(); // 等待左邊任務完成return leftResult + rightResult;}}public static void main(String[] args) {long[] array = new long[10000];// 初始化數組for (int i = 0; i < array.length; i++) {array[i] = i;}ForkJoinPool pool = new ForkJoinPool();ForkJoinSum task = new ForkJoinSum(array, 0, array.length);long result = pool.invoke(task);System.out.println("Sum: " + result);}
}

該示例展示了如何將一個大任務(數組求和)拆分成多個小任務,通過 Fork/Join 框架的工作竊取機制并行處理任務,并最終合并結果。

七、 并發容器解析

1. ConcurrentHashMap 的實現原理(JDK7 vs JDK8)

  • JDK7 實現原理

    • 分段鎖(Segment)機制:將整個 Map 劃分為多個 Segment,每個 Segment 內部維護一部分哈希桶。
    • 鎖定粒度較小:操作某個鍵值對時,僅鎖定所在的 Segment,讀操作大多無鎖,從而提升并發度。
    • 局限性:Segment 數量在創建時固定,可能存在熱點 Segment 導致爭用。
  • JDK8 實現原理

    • 取消分段鎖:直接使用一個 Node 數組作為底層結構,通過 CAS 操作實現無鎖更新。
    • 細粒度鎖:在發生沖突時,僅對鏈表或紅黑樹的某個桶加鎖,而非整個 Segment。
    • 鏈表轉紅黑樹:當單個桶中鏈表長度超過閾值時,轉換為紅黑樹以降低查找時間。
    • 優勢:讀操作完全無鎖,寫操作在沖突較少時可通過 CAS 完成,提高了整體性能和擴展性。

2. CopyOnWriteArrayList 的適用場景及優缺點

  • 適用場景

    • 讀操作遠遠多于寫操作的場景,如緩存、事件監聽器列表等。
    • 需要保證在迭代時數據不被修改,避免 ConcurrentModificationException 的情況。
  • 優點

    • 無鎖讀操作:迭代時不需要加鎖,性能高且線程安全。
    • 簡單安全:每次寫操作都會復制整個底層數組,保證了數據的一致性。
  • 缺點

    • 寫操作開銷大:每次更新都會復制整個數組,對于寫密集型應用效率低下。
    • 內存占用增加:復制操作會導致額外的內存消耗,適用于數據量較小且變更較少的場景。

3. BlockingQueue 的實現類及使用場景

  • ArrayBlockingQueue

    • 實現原理:基于數組實現的有界阻塞隊列,內部通過 ReentrantLock 來保證線程安全。
    • 使用場景:適用于固定容量的緩沖區,如生產者消費者模式中限制任務數量,防止過載。
  • LinkedBlockingQueue

    • 實現原理:基于鏈表實現,可設置有界或無界隊列,采用分離的 putLocktakeLock 提高并發性能。
    • 使用場景:適用于需要較大容量緩沖,或不希望受到固定數組大小限制的場景。
  • 其他實現類

    • PriorityBlockingQueue:基于優先級的無界阻塞隊列,適用于需要按照優先級處理任務的場景。
    • DelayQueue:基于延時策略的隊列,用于任務調度。
    • SynchronousQueue:每個插入操作必須等待對應的移除操作,適合于任務直接交給消費者處理的場景。

4. ConcurrentLinkedQueue 的無鎖實現原理

  • 基于鏈表的無鎖隊列:采用鏈表結構作為底層數據結構。
  • CAS 操作:利用 CAS(Compare-And-Swap)原子操作來保證在高并發環境下的線程安全,無需顯式鎖。
  • 頭尾指針維護:通過原子變量維護頭結點和尾結點,入隊和出隊操作通過 CAS 更新指針,保證數據一致性。
  • 優點:高并發情況下性能優越,避免了鎖競爭;
  • 缺點:在極端情況下可能存在短暫的不一致狀態,但總體上能夠保證最終一致性。

八、 并發設計模式與實戰

1. 生產者-消費者模式的實現方式

  • 阻塞隊列實現
    利用阻塞隊列(如 ArrayBlockingQueueLinkedBlockingQueue)實現任務緩沖區,生產者調用 put() 將任務放入隊列,消費者調用 take() 從隊列中獲取任務。
  • 等待/通知機制
    在共享緩沖區上使用 wait()notify()/notifyAll() 實現線程間通信,但需要小心處理虛假喚醒和同步問題。
  • 信號量機制
    通過 Semaphore 控制緩沖區中可用資源數量,協調生產者和消費者的訪問。

2. 如何實現線程安全的單例模式

  • 雙重檢查鎖定(DCL)
    在實例為空時進入同步代碼塊,再次檢查后創建實例。需要將實例聲明為 volatile,防止指令重排序導致問題。
  • 靜態內部類
    利用 JVM 類加載機制,在第一次使用時創建單例,既保證線程安全,又實現延遲加載。
  • 枚舉實現
    使用枚舉類型,JVM 會保證枚舉實例的唯一性和線程安全。

示例:使用雙重檢查鎖定實現線程安全的單例模式
(注意:Java代碼中的特殊字符已轉義)

public class Singleton {private static volatile Singleton instance;private Singleton() {// 防止反射調用if (instance != null) {throw new IllegalStateException("Already initialized");}}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

3. 如何排查和解決死鎖問題

排查方法

  • 使用線程轉儲(Thread Dump)工具分析線程的鎖持有情況;
  • 利用 JDK 內置的監控工具(如 VisualVM、JConsole、ThreadMXBean)檢測死鎖;
  • 檢查代碼中鎖的獲取順序是否一致,是否存在資源循環等待。

解決措施

  • 統一鎖順序:確保所有線程按照相同順序獲取多個鎖;
  • 使用超時鎖:采用 tryLock() 設置超時,避免長時間等待;
  • 細化鎖粒度:減少單個鎖保護的資源范圍,或采用無鎖算法與樂觀鎖。

4. 如何避免競態條件(Race Condition)

加鎖同步

  • 使用 synchronizedReentrantLock 等互斥機制,確保同一時間只有一個線程訪問共享數據。

原子操作

  • 利用原子類(如 AtomicIntegerAtomicLong)保證對單個變量的原子更新。

不可變對象設計

  • 使用不可變對象,避免在并發場景下對對象狀態的修改。

線程安全的集合

  • 采用并發容器(如 ConcurrentHashMapCopyOnWriteArrayList)管理共享數據,避免并發修改問題。

5. 如何設計高并發場景下的計數器

原子變量

  • 使用 AtomicIntegerAtomicLong 提供無鎖計數操作,適用于簡單的計數場景。

LongAdder/LongAccumulator

  • 在高并發場景下,使用 LongAdder(JDK8及以上)分散熱點,多個計數單元并行累加,最后合并結果。

分段計數器

  • 將計數器分為多個獨立部分,每個線程或線程組維護各自的局部計數,定期合并成全局計數,降低鎖競爭。

九、底層原理與擴展

1. Java 線程與操作系統線程的關系

  • 映射關系:Java 線程是由 JVM 映射到底層操作系統線程,通常采用 1:1 模型,即每個 Java 線程對應一個操作系統線程。
  • 操作系統調度:操作系統負責線程的調度、上下文切換等底層管理,JVM 則在此基礎上提供高級的線程管理功能,如線程池和并發工具。
  • 資源管理:底層線程由操作系統管理資源,Java 線程的創建、銷毀和調度都依賴于操作系統的支持。

2. 什么是協程(Coroutine)?Java 中的虛擬線程(Loom 項目)

  • 協程(Coroutine)

    • 協程是一種輕量級的線程實現,可以在單個線程中實現多個任務之間的切換。
    • 它通過保存和恢復執行上下文來實現并發執行,切換開銷遠低于操作系統線程的上下文切換。
    • 協程通常由用戶級庫調度,不依賴于操作系統的線程管理。
  • Java 中的虛擬線程(Loom 項目)

    • Project Loom 是 Java 的一個實驗性項目,旨在引入虛擬線程這一概念,使得創建成千上萬的線程成為可能。
    • 虛擬線程基于協程思想,能夠在用戶空間內高效調度,極大降低線程切換和資源消耗。
    • 該項目有望簡化并發編程模型,使得編寫高并發應用程序更加直觀和高效。

3. 如何通過 jstack 分析線程狀態

  • 生成線程堆棧信息:使用命令 jstack <pid>(其中 <pid> 是 Java 進程的標識)獲取當前線程的狀態及堆棧信息。
  • 分析線程狀態
    • 查看各線程的狀態,如 RUNNABLEWAITINGBLOCKED 等。
    • 檢查線程等待鎖和持有鎖的信息,確定是否存在死鎖或鎖競爭問題。
    • 根據堆棧信息定位長時間阻塞或運行緩慢的線程,幫助分析性能瓶頸或故障原因。

4. 什么是偽共享(False Sharing)?如何避免?

  • 偽共享定義

    • 當多個線程在不同的變量上操作時,如果這些變量恰好位于同一個 CPU 緩存行中,會引起頻繁的緩存行失效和重載,進而影響性能。
  • 避免方法

    • 內存填充(Padding):通過在變量之間添加無用的數據字段(例如額外的 long 型字段)來確保它們不在同一緩存行上。
    • 使用 @Contended 注解:在 Java 8 及以上版本中,可以使用 @Contended 注解標記容易發生偽共享的變量(需在 JVM 啟動參數中啟用 -XX:-RestrictContended)。
    • 合理的數據結構設計:在設計并發數據結構時,考慮將易沖突的變量分散到不同的緩存行中,減少互相影響。

十、其他擴展問題

1. 如何實現異步編程(如 CompletableFuture、Reactive Streams)?

CompletableFuture

  • CompletableFuture 是 Java 8 引入的異步編程工具,它支持鏈式操作,可以避免傳統回調地獄(Callback Hell)。
  • 主要方法包括 supplyAsync()thenApply()thenAccept()thenCompose()handle() 等。
import java.util.concurrent.CompletableFuture;public class AsyncExample {public static void main(String[] args) {CompletableFuture.supplyAsync(() -> {return "Hello, World!";}).thenApply(result -> {return result + " - Processed";}).thenAccept(System.out::println);}
}

Reactive Streams

  • Reactive Streams 是一種基于發布-訂閱模式的異步處理標準,支持 非阻塞背壓(Back Pressure) 機制。
  • 常見實現有 Project Reactor(Spring WebFlux)和 RxJava
  • 核心組件:
    • Publisher(發布者):生產數據流。
    • Subscriber(訂閱者):消費數據流。
    • Subscription(訂閱):連接 PublisherSubscriber,管理數據傳輸速率。
    • Processor(處理器):既是 Publisher 也是 Subscriber,可對流數據進行處理。

2. 分布式鎖與單機鎖的區別

單機鎖

  • 僅用于單個 JVM 內部,保證線程間同步
  • 實現方式
    • synchronized 關鍵字
    • ReentrantLock 可重入鎖
  • 優點:實現簡單、開銷低。
  • 缺點:無法跨進程或跨服務器同步。

分布式鎖

  • 用于多個進程或服務器之間的同步控制。
  • 常見實現
    • 基于 Redis:如 SET NX EX 方式。
    • 基于 ZooKeeper:利用 EPHEMERAL(臨時節點)實現鎖。
    • 基于數據庫:使用數據庫表中的唯一字段實現鎖(效率較低)。
  • 優點:支持跨服務同步,防止分布式環境下的數據競爭。
  • 缺點:實現復雜,需要考慮網絡延遲、鎖超時、鎖丟失等問題。
import redis.clients.jedis.Jedis;public class RedisLock {private Jedis jedis;private String lockKey = "distributed_lock";public RedisLock(Jedis jedis) {this.jedis = jedis;}public boolean lock() {return "OK".equals(jedis.set(lockKey, "locked", "NX", "EX", 10));}public void unlock() {jedis.del(lockKey);}
}

3. 無鎖編程(Lock-Free)的實現思路

CAS(Compare-And-Swap)

  • CAS 操作:比較并交換,保證多個線程同時更新時的原子性。
  • Java 中的無鎖實現
    • AtomicInteger
    • AtomicLong
    • AtomicReference
  • 缺點
    • 可能出現 ABA 問題(即值改變了但看起來未變)。
    • 高并發下可能導致 自旋過多,消耗 CPU
import java.util.concurrent.atomic.AtomicInteger;public class CASExample {private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) {count.incrementAndGet(); // 使用 CAS 增加計數System.out.println("Counter: " + count.get());}
}

樂觀鎖

  • 原理:不主動加鎖,而是在更新前檢查數據版本,若檢測到沖突則重試。
  • 實現方式
    • CAS(Compare-And-Swap) 操作
    • 版本號機制(如數據庫的 version 字段)
  • 適用于:高并發、沖突較少的場景。

無鎖數據結構

  • 設計時避免使用鎖,如 ConcurrentLinkedQueue 采用 CAS + 鏈表的方式更新數據。
  • 示例
    • ConcurrentLinkedQueue
    • LongAdder(分段計數,減少鎖競爭)
    • CopyOnWriteArrayList(寫時復制)

4. 高并發場景下常見的性能優化手段

1. 減少鎖競爭

  • 使用 細粒度鎖分段鎖 降低鎖競爭。
  • 無鎖數據結構 代替同步容器(如 ConcurrentHashMap)。
  • 讀寫鎖 代替互斥鎖(ReentrantReadWriteLock)。

2. 線程池優化

  • 合理配置線程池
    • CPU 密集型任務:線程數 = CPU 核心數 + 1
    • IO 密集型任務:線程數 = CPU 核心數 * 2
  • 避免頻繁創建/銷毀線程,實現線程復用

3. 緩存機制

  • 本地緩存(如 CaffeineGuava Cache)。
  • 分布式緩存(如 RedisMemcached)。
  • 讀寫分離數據預熱,減少數據庫壓力。

4. 異步 & 批量處理

  • 采用消息隊列(MQ),如 KafkaRabbitMQ 進行異步處理。
  • 批量操作(如數據庫批量插入 batch insert)。

5. 數據結構優化

  • 選擇合適的數據結構,避免不必要的鎖競爭:
    • ConcurrentHashMap 代替 Hashtable
    • CopyOnWriteArrayList 代替 ArrayList(適用于讀多寫少的場景)
  • 避免偽共享(False Sharing),通過 緩存行填充 提高 CPU 緩存命中率。

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

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

相關文章

【STM32】第一個工程的創建

目錄 1、獲取 KEIL5 安裝包2、開始安裝 KEIL52.1、 激活2.2、安裝DFP庫 3、工程創建4、搭建框架5、開始編寫代碼 1、獲取 KEIL5 安裝包 要想獲得 KEIL5 的安裝包&#xff0c;在百度里面搜索“KEIL5 下載”即可找到很多網友提供的下載文件&#xff0c;或者到 KEIL 的官網下載&a…

動態規劃~01背包問題

01背包問題 經典的0 - 1背包問題的解決方案。 二維數組的版本 代碼功能概述 0 - 1背包問題指的是有 n 個物品和一個容量為 m 的背包&#xff0c;每個物品有對應的體積 v[i] 和價值 w[i]&#xff0c;需要從這些物品里挑選若干個放入背包&#xff0c;讓背包內物品的總價值達到最…

深入理解Java享元模式及其線程安全實踐

引言 在軟件系統中&#xff0c;當需要處理海量細粒度對象時&#xff0c;直接創建大量實例可能會導致內存消耗激增和性能下降。享元模式&#xff08;Flyweight Pattern&#xff09;通過共享對象內部狀態&#xff0c;成為解決這類問題的經典方案。然而在多線程環境下&#xff0c…

1、mysql基礎篇--概述

關系型數據庫&#xff08;RDBMS&#xff09; 概念特點&#xff1a;數據模型&#xff1a; 概念 建立在關系模型基礎上&#xff0c;有多張表相互連接的二維表組成的數據庫 特點&#xff1a; 1、使用表存儲&#xff0c;格式統一&#xff0c;便于維護 2、使用sql語言操作&#…

如何提升庫存系統的高并發和穩定性:算法與設計模式

庫存系統是企業運營的核心模塊&#xff0c;尤其是在電商、零售和供應鏈管理中&#xff0c;系統的高并發和穩定性直接影響訂單處理的準確性和效率。面對海量訂單、復雜的庫存管理需求&#xff0c;如何在高并發環境下確保庫存數據的準確性和系統的穩定性&#xff1f;本文將從架構…

【多線程】synchronized底層實現的方式

前言 在java 開發中對于鎖的應用非常的常見&#xff0c;如果對于什么時候該用什么鎖&#xff0c;以及鎖實現的原理有所不知道的&#xff0c;或者面試過程中面試官問你不知道怎么回答的&#xff0c;歡迎來看下面的文章 1、synchronized和ReentrantLock的區別 2、synchronized的…

Pytorch中Tensorboard的學習

1、Tensorboard介紹 TensorBoard 是 TensorFlow 開發的一個可視化工具&#xff0c;用于幫助用戶理解和調試機器學習模型的訓練過程。盡管它最初是為 TensorFlow 設計的&#xff0c;但通過 PyTorch 的 torch.utils.tensorboard 模塊&#xff0c;PyTorch 用戶也可以方便地使用 Te…

ETL 自動化:提升數據處理效率與準確性的核心驅動力

在數字化轉型的浪潮中&#xff0c;數據已成為企業戰略資產&#xff0c;高效處理數據的能力直接關系到企業的競爭力。ETL&#xff08;Extract, Transform, Load&#xff09;自動化作為數據處理領域的關鍵技術&#xff0c;正逐漸成為企業在數據時代脫穎而出、實現高效運營與精準決…

std::endl為什么C++ 智能提示是函數?

在使用vscode 的C智能提示后&#xff0c;輸入endl 后&#xff0c;提示的卻是std::endl(basic_ostream<CharT, Traits> &os), 感覺比較奇怪&#xff0c;各種代碼里都是直接用的std::endl 啊&#xff0c; 這里怎么變成函數了呢&#xff1f; 在 C 中&#xff0c;std::en…

簡潔、實用、無插件和更安全為特點的WordPress主題

簡站WordPress主題是一款以簡潔、實用、無插件和更安全為特點的WordPress主題&#xff0c;自2013年創立以來&#xff0c;憑借其設計理念和功能優勢&#xff0c;深受用戶喜愛。以下是對簡站WordPress主題的詳細介紹&#xff1a; 1. 設計理念 簡站WordPress主題的核心理念是“崇…

數據結構篇:空間復雜度和時間復雜度

目錄 1.前言&#xff1a; 1.1 學習感悟 1.2 數據結構的學習之路(初階) 2.什么是數據結構和算法 2.1 數據結構和算法的關系 2.2 算法的重要性 2.3 如何衡量算法的好壞 3.時間復雜度 3.1 時間復雜度的概念 3.2 大O的漸進表示法 O() 4.空間復雜度 5. 常見的時間復雜度和…

node-ddk,electron,截屏封裝(js-web-screen-shot)

node-ddk 截屏封裝(js-web-screen-shot) https://blog.csdn.net/eli960/article/details/146207062 也可以下載demo直接演示 http://linuxmail.cn/go#node-ddk 感謝/第三方 本截屏工具, 使用的是: js-web-screen-shot https://www.npmjs.com/package/vue-web-screen-shot…

泰坦軍團攜手順網旗下電競連鎖品牌樹呆熊 共創電競新紀元

在電競行業的浪潮中&#xff0c;品牌之間的戰略合作愈發成為推動市場前行的重要動力。最近&#xff0c;電競顯示器領域領軍品牌泰坦軍團高層領導出席順網旗下電競連鎖品牌樹呆熊十周年盛典。會議現場&#xff0c;雙方高層領導宣布泰坦軍團與樹呆熊正式達成戰略合作伙伴關系。 在…

HandyJSON原理

HandyJSON 的優勢 JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式, 應用廣泛. 在 App 的使用過程中, 服務端給移動端發送的大部分都是 JSON 數據, 移動端需要解析數據才能做進一步的處理. 在解析JSON數據這一塊, 目前 Swift 中流行的框架基本上是 SwiftyJSON, …

信號的產生和保存

信號的產生 信號就是操作系統對用戶操作做出的反應&#xff0c;但它的本質就是往操作系統寫入信號&#xff0c;這是由操作系統的結構決定的。通過修改比特位來告訴操作系統接收信號和傳了幾號信號。 也正是因為我們身為用戶無法親自修改內核數據&#xff0c;所以我們需要通過操…

在C++ Qt中集成Halcon窗口并實現跨平臺兼容和大圖加載

目錄 1. Halcon窗口嵌入Qt Widget 2. 處理大圖加載 3. 多線程優化顯示 4. 跨平臺兼容性 1. Halcon窗口嵌入Qt Widget 將Halcon的HWindow控件嵌入到Qt的QWidget容器中,利用系統原生句柄實現跨平臺。 #include <HalconCpp.h> #include <QWidget>class HalconWi…

深度學習技術與應用的未來展望:從基礎理論到實際實現

深度學習作為人工智能領域的核心技術之一&#xff0c;近年來引起了極大的關注。它不僅在學術界帶來了革命性的進展&#xff0c;也在工業界展現出了廣泛的應用前景。從圖像識別到自然語言處理&#xff0c;再到強化學習和生成對抗網絡&#xff08;GAN&#xff09;&#xff0c;深度…

藍光三維掃描技術:汽車零部件檢測的精準高效之選

——汽車方向盤配件、保險杠塑料件、鈑金件檢測項目 汽車制造工業的蓬勃發展&#xff0c;離不開強大的零部件制造體系作支撐。汽車零部件作為汽車工業的基礎&#xff0c;其設計水平、制造工藝、質量控制手段逐漸與國際標準接軌&#xff0c;對于零部件面差、孔位、圓角、特征線…

數據庫聯表Sql語句建一個新表(MySQL,Postgresql,SQL server)

數據庫聯表Sql語句建一個新表(MySQL,Postgresql,SQL server) 如果你想基于 SELECT USERS.ID,USERS.NAME,USERS.EMAIL,USERS.ID_CARD,USERS.V_CARD,USERS.ADDRESS,v_card.type,v_card.amount FROM USERS JOIN v_card on USERS.V_CARDv_card.v_card 這個查詢結果創建一個新表&am…

六十天前端強化訓練之第三十天之深入解析Vue3電商項目:TechStore全棧實踐(文結尾附有源代碼)

歡迎來到編程星辰海的博客講解 看完可以給一個免費的三連嗎&#xff0c;謝謝大佬&#xff01; 目錄 深入解析Vue3電商項目&#xff1a;TechStore全棧實踐 一、項目架構設計 二、核心功能實現 三、組合式API深度實踐 四、性能優化實踐 五、項目擴展方向 六、開發經驗總結…