最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)編程中高頻異常的原因,場景與解決方案全解析

 更新時間:2026年03月09日 09:27:07   作者:Akk_it  
在Java并發(fā)編程中,異常處理是保障程序穩(wěn)定性的核心環(huán)節(jié),本文將深度解析4類高頻并發(fā)異常的產生原因、典型場景,并給出可落地的解決方案,幫你徹底避開這些坑

在 Java 并發(fā)編程中,異常處理是保障程序穩(wěn)定性的核心環(huán)節(jié)。新手開發(fā)者常常會被InterruptedExceptionIllegalMonitorStateException等并發(fā)相關異常困擾,這些異常不僅定位困難,還可能導致程序死鎖、數據錯亂甚至服務崩潰。本文將深度解析 4 類高頻并發(fā)異常的產生原因、典型場景,并給出可落地的解決方案,幫你徹底避開這些 “坑”。

一、java.lang.InterruptedException(中斷異常)

1. 異常本質

InterruptedException受檢異常,表示線程在執(zhí)行阻塞操作(如sleep()wait())時被其他線程中斷,導致阻塞狀態(tài)被強制打斷。

2. 觸發(fā)場景

當線程調用Thread.sleep(long)Object.wait()、Thread.join()等阻塞方法時,其他線程調用該線程的interrupt()方法,就會觸發(fā)此異常。

3. 錯誤示例

public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                // 線程休眠10秒
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println("線程休眠被中斷:" + e.getMessage());
                // 重置中斷狀態(tài)(關鍵!)
                Thread.currentThread().interrupt();
            }
        });
        t1.start();
        
        // 1秒后中斷t1線程
        Thread.sleep(1000);
        t1.interrupt();
    }
}

4. 解決方案

  • 捕獲異常后重置中斷狀態(tài):異常會清除線程的中斷標記,需調用Thread.currentThread().interrupt()恢復,避免后續(xù)邏輯無法感知中斷。
  • 優(yōu)雅處理中斷:不要吞掉異常,根據業(yè)務場景決定是否終止線程(如任務取消時)。

二、java.lang.IllegalMonitorStateException(非法監(jiān)視器狀態(tài)異常)

1. 異常本質

調用wait()、notify()、notifyAll()時,當前線程未持有該對象的監(jiān)視器鎖(即未進入synchronized塊 / 方法),或鎖對象與調用方法的對象不一致。

2. 觸發(fā)場景

  • 場景 1:未在synchronized塊內調用wait()/notify();
  • 場景 2:synchronized鎖定的對象 ≠ 調用wait()的對象;
  • 場景 3:混用LockCondition.await()/signal())和synchronizedwait()/notify())。

3. 錯誤示例 vs 正確示例

錯誤示例(未加 synchronized)

public class IllegalMonitorDemo {
    private static final Object lock = new Object();
    
    public static void main(String[] args) {
        // 直接調用wait(),未持有l(wèi)ock的鎖
        lock.wait(); // 拋出IllegalMonitorStateException
    }
}

正確示例

public class IllegalMonitorDemo {
    private static final Object lock = new Object();
    
    public static void main(String[] args) throws InterruptedException {
        synchronized (lock) { // 必須先獲取lock的監(jiān)視器鎖
            lock.wait(); // 正確:當前線程持有l(wèi)ock的鎖
        }
    }
}

4. 解決方案

核心原則:調用wait()/notify()的代碼必須在synchronized塊 / 方法內,且鎖定的對象必須是調用這些方法的對象;

Lock+Condition 用法:若使用ReentrantLock,需通過Condition.await()/signal()替代wait()/notify(),且調用前需獲取Lock鎖:

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock(); // 獲取鎖
try {
    condition.await(); // 替代wait()
} finally {
    lock.unlock(); // 釋放鎖
}

三、java.util.ConcurrentModificationException(并發(fā)修改異常)

1. 異常本質

單線程下迭代集合時修改集合(如 add/remove),或多線程同時修改非線程安全集合(如ArrayList),導致迭代器檢測到集合結構被意外修改。

2. 觸發(fā)場景

ArrayList、HashMap等集合的方法(add()、remove())未加鎖,多線程并發(fā)修改時,迭代器的modCount(修改次數)與expectedModCount不一致,觸發(fā)異常。

3. 錯誤示例(多線程修改 ArrayList)

public class ConcurrentModificationDemo {
    private static final List<Integer> list = new ArrayList<>();
    
    public static void main(String[] args) {
        // 線程1:循環(huán)添加元素
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                list.add(i);
            }
        }).start();
        
        // 線程2:循環(huán)迭代并修改
        new Thread(() -> {
            for (Integer num : list) { // 迭代時觸發(fā)檢查
                list.remove(num); // 拋出ConcurrentModificationException
            }
        }).start();
    }
}

4. 解決方案

  • 單線程場景:迭代時修改集合需使用迭代器的remove()方法,而非集合的remove();
  • 多線程場景
    • 方案 1:使用線程安全集合(如CopyOnWriteArrayList、ConcurrentHashMap);
    • 方案 2:對非線程安全集合加鎖(如synchronizedReentrantLock);
    • 方案 3:使用Collections.synchronizedList(new ArrayList<>())包裝集合(注意:迭代時仍需手動加鎖)。

正確示例(CopyOnWriteArrayList)

// 線程安全的ArrayList替代方案
private static final List<Integer> list = new CopyOnWriteArrayList<>();

四、java.util.concurrent.RejectedExecutionException(拒絕執(zhí)行異常)

1. 異常本質

向線程池提交任務時,線程池已達到最大處理能力(核心線程 + 非核心線程 + 任務隊列均滿),且拒絕策略為AbortPolicy(默認),導致任務被拒絕執(zhí)行。

2. 觸發(fā)場景

線程池參數配置不合理,提交的任務數超過其最大容量:

  • 核心線程數:corePoolSize;
  • 最大線程數:maximumPoolSize;
  • 任務隊列容量:workQueue.size();
  • 最大可處理任務數 = maximumPoolSize + workQueue.size()。

3. 錯誤示例(任務數超過線程池容量)

public class RejectedExecutionDemo {
    public static void main(String[] args) {
        // 配置線程池:核心2,最大5,隊列10,拒絕策略AbortPolicy
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, 5, 60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(10),
            new ThreadPoolExecutor.AbortPolicy() // 默認拒絕策略:直接拋異常
        );
        
        // 提交16個任務(最大容量5+10=15),第16個被拒絕
        for (int i = 0; i < 16; i++) {
            int finalI = i;
            executor.submit(() -> {
                try {
                    Thread.sleep(1000);
                    System.out.println("執(zhí)行任務:" + finalI);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        executor.shutdown();
    }
}

4. 解決方案

  • 合理配置線程池參數:根據業(yè)務場景調整corePoolSize、maximumPoolSize、隊列容量,避免任務堆積;
  • 選擇合適的拒絕策略
    • AbortPolicy:默認,拋異常(適合核心任務,需感知任務拒絕);
    • CallerRunsPolicy:由提交任務的線程執(zhí)行(降級處理,避免任務丟失);
    • DiscardPolicy:靜默丟棄任務(非核心任務);
    • DiscardOldestPolicy:丟棄隊列最老的任務,嘗試提交新任務;
  • 異步降級:結合消息隊列(如 RabbitMQ)削峰填谷,避免瞬時任務量超過線程池承載能力。

優(yōu)化示例(使用 CallerRunsPolicy)

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 5, 60L, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(10),
    new ThreadPoolExecutor.CallerRunsPolicy() // 提交線程執(zhí)行被拒絕的任務
);

總結

本文梳理了 Java 并發(fā)編程中 4 類高頻異常的核心要點,關鍵總結如下:

  • InterruptedException:阻塞方法被中斷時拋出,捕獲后需重置中斷狀態(tài),避免吞掉異常;
  • IllegalMonitorStateException:調用 wait/notify 前必須持有對象的監(jiān)視器鎖,Lock 需搭配 Condition 使用;
  • ConcurrentModificationException:非線程安全集合并發(fā)修改觸發(fā),優(yōu)先使用 CopyOnWriteArrayList/ConcurrentHashMap;
  • RejectedExecutionException:線程池任務超限觸發(fā),需合理配置參數 + 選擇合適的拒絕策略。

以上就是Java并發(fā)編程中高頻異常的原因,場景與解決方案全解析的詳細內容,更多關于Java并發(fā)編程高頻異常的資料請關注腳本之家其它相關文章!

相關文章

  • Java 基于AQS實現一個同步器

    Java 基于AQS實現一個同步器

    這篇文章主要介紹了如何基于AQS實現一個同步器,幫助大家更好的理解和學習Java并發(fā),感興趣的朋友可以了解下
    2020-09-09
  • IntelliJ IDEA中使用mybatis-generator的示例

    IntelliJ IDEA中使用mybatis-generator的示例

    這篇文章主要介紹了IntelliJ IDEA中使用mybatis-generator,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • SpringBoot讀取Resource目錄文件的五種常見方式

    SpringBoot讀取Resource目錄文件的五種常見方式

    在Spring Boot開發(fā)中,我們經常需要讀取src/main/resources目錄下的文件,src/main/resources 目錄下通常存放配置文件、模板、靜態(tài)資源、SQL腳本等,本文給大家介紹了SpringBoot讀取Resource目錄文件的五種常見方式,需要的朋友可以參考下
    2025-07-07
  • Java使用HashMap映射實現消費抽獎功能

    Java使用HashMap映射實現消費抽獎功能

    這篇文章主要為大家詳細介紹了Java使用HashMap映射實現消費抽獎功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringCloud與Consul集成實現負載均衡功能

    SpringCloud與Consul集成實現負載均衡功能

    負載均衡基本概念有:實服務、實服務組、虛服務、調度算法、持續(xù)性等,其常用應用場景主要是服務器負載均衡,鏈路負載均衡。這篇文章主要介紹了SpringCloud與Consul集成實現負載均衡 ,需要的朋友可以參考下
    2018-09-09
  • spring boot tomcat jdbc pool的屬性綁定

    spring boot tomcat jdbc pool的屬性綁定

    這篇文章主要介紹了spring boot tomcat jdbc pool的屬性綁定的相關資料,非常不錯,具有參考借鑒價值,需要的朋友參考下
    2018-01-01
  • java前后端傳值,參數有集合類型的數據時的兩種操作方式

    java前后端傳值,參數有集合類型的數據時的兩種操作方式

    這篇文章主要介紹了java前后端傳值,參數有集合類型的數據時的兩種操作方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • JAVA中調用C語言函數的實現方式

    JAVA中調用C語言函數的實現方式

    這篇文章主要介紹了JAVA中調用C語言函數的實現方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Mac?Maven環(huán)境搭建安裝和配置超詳細步驟

    Mac?Maven環(huán)境搭建安裝和配置超詳細步驟

    這篇文章主要給大家介紹了關于Mac?Maven環(huán)境搭建安裝和配置的超詳細步驟,Maven是一種常用的Java構建工具,它可以自動化構建、測試和打包Java項目,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • 深入淺析jcmd:JDK14中的調試神器

    深入淺析jcmd:JDK14中的調試神器

    這篇文章主要介紹了jcmd:JDK14中的調試神器,本文給大家提到了jcmd的語法,通過實例列舉的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04

最新評論

五莲县| 吴江市| 吐鲁番市| 宾川县| 霞浦县| 阳东县| 竹北市| 夹江县| 纳雍县| 商都县| 巴彦县| 达日县| 临海市| 博爱县| 泸溪县| 西平县| 南召县| 长泰县| 内黄县| 新干县| 淮北市| 嵊泗县| 涿鹿县| 裕民县| 新竹县| 汤原县| 隆昌县| 商丘市| 营口市| 临沧市| 正宁县| 利津县| 澄城县| 淮滨县| 清涧县| 莆田市| 清苑县| 临朐县| 保靖县| 周至县| 化德县|