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

Java中的fail-fast機(jī)制使用詳解

 更新時(shí)間:2025年01月08日 14:53:10   作者:夜夜流光相皎潔_小寧  
fail-fast機(jī)制是Java集合中用于檢測(cè)并發(fā)修改的一種機(jī)制,當(dāng)一個(gè)線程遍歷集合時(shí),如果集合被其他線程修改,就會(huì)拋出ConcurrentModificationException異常,解決fail-fast機(jī)制的方法包括使用普通for循環(huán)、Iterator

Java的fail-fast機(jī)制使用

fail-fast 機(jī)制是Java集合(Collection)中的一種錯(cuò)誤機(jī)制。當(dāng)多個(gè)線程對(duì)同一個(gè)集合的內(nèi)容進(jìn)行操作時(shí),就可能會(huì)產(chǎn)生fail-fast事件。

例如:

  • 當(dāng)某一個(gè)線程 A 通過 iterator 去遍歷某集合的過程中,若該集合的內(nèi)容被其他線程所改變了,那么線程 A 訪問集合時(shí),就會(huì)拋出 ConcurrentModificationException 異常,產(chǎn)生 fail-fast 事件。
  • 這里的操作主要是指 add、remove 和 clear,對(duì)集合元素個(gè)數(shù)進(jìn)行修改。

舉例代碼

單線程,在foreach循環(huán)里對(duì)某些集合元素進(jìn)行元素的remove/add操作的時(shí)候,會(huì)觸發(fā)fail-fast機(jī)制

public static void main(String[] args){
  List<String> strList = new ArrayList<>();
  strList.add("AA");
  strList.add("aa");
  strList.add("BB");
  strList.add("CC");
  for(String str : strList){
     if("aa".equals(str)){
       strList.remove(str);
     }
  }
}

多線程,在一個(gè)線程讀時(shí),另一個(gè)線程寫入list,讀線程會(huì)fail-fast

// 測(cè)試
public class TreadDemo1 {
   public static void main(String[] args){
        List<String> strList = new ArrayList<>();
        strList.add("AA");
        strList.add("aa");
        strList.add("BB");
        strList.add("CC");
        strList.add("DD");
        new MyThread1(strList).start();
        new MyThread2(strList).start();
   }
   static class Mythread1 extends Thread {
       private List<String> list;
       public Mythread1(List<String> list){
             this.list = list;
       }
       @Override
       public void run(){
             for(String str : list){
                 try{
                     Thread.sleep(100);
                 }catch(InterruptedException e){
                     e.printStackTrace();
                 }
                 System.out.println("MtThread1:"+str);
             }
       }
  }
  static class MyThread2 extends Thread {
       private list<String> list;
       public Mythread2(List<String> list){
             this.list = list;
       }
       @Override
       public void run(){
             for(int i = 0; i < list.size(); i++){
                 try{
                     Thread.sleep(100);
                 }catch(InterruptedException e){
                     e.printStackTrace();
                 }
                 if("aa".equals(list.get(i))){
                     list.remove(i);
                 }
             }
             System.out.println("MtThread2:"+list);
       }
  }
}

原理

將單線程編譯后的.class反編譯后發(fā)現(xiàn),foreach其實(shí)是依賴while循環(huán)和Iterator實(shí)現(xiàn)的。

通過跟蹤代碼的異常堆棧,發(fā)現(xiàn)真正拋出異常的代碼是:java.util.ArrayList$Itr.checkForComodification();該方法實(shí)在iterator.next()方法中調(diào)用的:

final void checkForComodification(){
      if(modCount != expectedModCount)
           throw new ConcurrentModificationException();
}

在該方法中modCount 和 expectedModCount進(jìn)行了比較,如果二者不相等,則拋出ConcurrentModificationException 異常。

  • modCount是ArrayList中的一個(gè)成員變量。表示該集合實(shí)際被修改的次數(shù)。(操作集合類的remove()、add()、clear()方法會(huì)改變這個(gè)變量值)
  • expectedModCount是ArrayList 中的一個(gè)內(nèi)部類---Itr(Iterator接口)中的成員變量。表示這個(gè)迭代器預(yù)期該集合被修改的次數(shù)。其值隨著Itr被創(chuàng)建而初始化。只有通過迭代器對(duì)集合進(jìn)行操作,該值才會(huì)改變。

所以,在使用Java的集合類的時(shí)候,如果發(fā)生ConcurrentModificationException 異常,優(yōu)先考慮fail-fast有關(guān)的情況。

解決方式

1)使用普通for循環(huán)進(jìn)行操作

普通for循環(huán)沒有使用到Iterator的遍歷,所以不會(huì)進(jìn)行fail-fast的檢驗(yàn)。

public static void main(String[] args){
        List<String> strList = new ArrayList<>();
        strList.add("AA");
        strList.add("aa");
        strList.add("BB");
        strList.add("CC");
        strList.add("DD");
        for(int i = 0; i < strList.size(); i++){
                 if("aa".equals(strList.get(i))){
                     strList.remove(i);
                 }
        }
   }

2)直接使用Iterator 進(jìn)行操作

public static void main(String[] args){
        List<String> strList = new ArrayList<>();
        strList.add("AA");
        strList.add("aa");
        strList.add("BB");
        strList.add("CC");
        strList.add("DD");
        Iterator<String> iterator = strList.iterator();
        while(iterator.hasNext()){
             if("aa".equals(iterator.next())){
                iterator.remove();
             }
        }
   }

3)使用Java 8中提供的filter 過濾

Java 8 中可以把集合轉(zhuǎn)換成流,對(duì)于流有一種filter操作,可以對(duì)原始Stream 進(jìn)行某項(xiàng)過濾,通過過濾的元素被留下了生成一個(gè)新的Stream。

public static void main(String[] args){
        List<String> strList = new ArrayList<>();
        strList.add("AA");
        strList.add("aa");
        strList.add("BB");
        strList.add("CC");
        strList.add("DD");
        strList = strList.stream().filter(e -> !"aa".equals(e)).collect(Collectors.toList());
        System.out.println(strList);
   }

4)使用fail-safe的集合類

為了避免觸發(fā)fail-fast機(jī)制導(dǎo)致異常,我們可以使用Java中提供的一些采用了fail-safe機(jī)制的集合類。

java.util.concurrent包下的容器都是fail-safe的,可以在多線程下并發(fā)使用,并發(fā)修改。同時(shí)也可以在foreach中進(jìn)行add/remove等操作。

5)也可以使用foreach循環(huán)

如果我們非常確定一個(gè)集合中,某個(gè)即將刪除的元素只包含一個(gè)的話,也是可以使用foreach循環(huán)的,只要?jiǎng)h除之后,立即結(jié)束循環(huán)體,不在繼續(xù)執(zhí)行遍歷就可以。

public static void main(String[] args){
  List<String> strList = new ArrayList<>();
  strList.add("AA");
  strList.add("aa");
  strList.add("BB");
  strList.add("CC");
  for(String str : strList){
     if("aa".equals(str)){
       strList.remove(str);
       break;
     }
  }
  System.out.println(strList);
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)調(diào)用對(duì)方http接口得到返回?cái)?shù)據(jù)

    Java實(shí)現(xiàn)調(diào)用對(duì)方http接口得到返回?cái)?shù)據(jù)

    這篇文章主要介紹了Java實(shí)現(xiàn)調(diào)用對(duì)方http接口得到返回?cái)?shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring Security SecurityContextHolder組件示例說明

    Spring Security SecurityContextHolder組件示例說明

    SpringSecurity的SecurityContextHolder組件是存儲(chǔ)當(dāng)前安全上下文的地方,包括認(rèn)證用戶信息,它支持全局訪問、線程局部存儲(chǔ)和上下文傳播,是SpringSecurity認(rèn)證和授權(quán)的核心,文章通過示例展示了如何訪問已認(rèn)證用戶的詳細(xì)信息、手動(dòng)設(shè)置認(rèn)證信息以及使用認(rèn)證信息保護(hù)方法
    2024-11-11
  • SpringBoot?AnnotationUtils工具類的使用實(shí)例詳解

    SpringBoot?AnnotationUtils工具類的使用實(shí)例詳解

    這篇文章主要介紹了SpringBoot?AnnotationUtils工具類的使用,使用自定義注解標(biāo)記業(yè)務(wù)方法,原生Java獲取注解及AnnotationUtils工具類獲取方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 基于spring DI的三種注入方式分析

    基于spring DI的三種注入方式分析

    這篇文章主要介紹了基于spring DI的三種注入方式分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2021-07-07
  • Java字符編碼轉(zhuǎn)換(從UTF-8到GBK)的實(shí)現(xiàn)原理與實(shí)踐

    Java字符編碼轉(zhuǎn)換(從UTF-8到GBK)的實(shí)現(xiàn)原理與實(shí)踐

    在計(jì)算機(jī)處理文本的過程中,字符編碼轉(zhuǎn)換是跨語言、跨平臺(tái)數(shù)據(jù)交互的核心環(huán)節(jié),本文詳細(xì)介紹了Java中Unicode與GBK字符集之間的映射原理及UTF-8與GBK編碼之間的轉(zhuǎn)換邏輯,幫助開發(fā)者理解底層機(jī)制并避免編碼問題,需要的朋友可以參考下
    2026-01-01
  • @Async異步線程池以及線程的命名方式

    @Async異步線程池以及線程的命名方式

    這篇文章主要介紹了@Async異步線程池以及線程的命名方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • MybatisX-Generator不生成domain文件夾的問題及解決

    MybatisX-Generator不生成domain文件夾的問題及解決

    在使用MybatisX-Generator生成數(shù)據(jù)庫表實(shí)體時(shí),如果發(fā)現(xiàn)沒有生成domain文件夾以及User.java文件,是因?yàn)镸ybatisX版本更新,最新版需要在options里額外勾選model才能生成domain,勾選model并點(diǎn)擊finish后,成功生成domain文件夾及User.java文件
    2025-01-01
  • 簡(jiǎn)單了解Java程序運(yùn)行整體流程

    簡(jiǎn)單了解Java程序運(yùn)行整體流程

    這篇文章主要介紹了簡(jiǎn)單了解Java程序運(yùn)行整體流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java生成jar包的方法

    java生成jar包的方法

    這篇文章主要介紹了java生成jar包的方法,對(duì)Java生成jar包的具體步驟及方法進(jìn)行了較為詳細(xì)的描述,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-09-09
  • Java大數(shù)字運(yùn)算之BigInteger

    Java大數(shù)字運(yùn)算之BigInteger

    在Java中提供了大數(shù)字的操作類,即 java.math.BigInteger 類與 java.math.BigDecimal 類。其中,BigInteger 類是針對(duì)大整數(shù)的處理類,這里有Integer 類的解釋,使用方法和實(shí)例,需要的朋友可以參考下。
    2017-08-08

最新評(píng)論

盘山县| 丹江口市| 昆山市| 临沭县| 湘乡市| 霍邱县| 阳泉市| 汤阴县| 江安县| 玉龙| 平远县| 江阴市| 彰武县| 旺苍县| 临朐县| 吴江市| 那坡县| 二连浩特市| 泰兴市| 安达市| 衢州市| 巫溪县| 彭阳县| 龙游县| 靖宇县| 广丰县| 和林格尔县| 美姑县| 奎屯市| 荥阳市| 荆州市| 绥芬河市| 新绛县| 济南市| 灵丘县| 汉寿县| 阳原县| 长乐市| 安宁市| 长岭县| 绥中县|