欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的fail-fast機制使用詳解

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

Java的fail-fast機制使用

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

例如:

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

舉例代碼

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

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);
     }
  }
}

多線程,在一個線程讀時,另一個線程寫入list,讀線程會fail-fast

// 測試
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其實是依賴while循環(huán)和Iterator實現(xiàn)的。

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

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

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

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

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

解決方式

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

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

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)換成流,對于流有一種filter操作,可以對原始Stream 進(jìn)行某項過濾,通過過濾的元素被留下了生成一個新的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機制導(dǎo)致異常,我們可以使用Java中提供的一些采用了fail-safe機制的集合類。

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

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

如果我們非常確定一個集合中,某個即將刪除的元素只包含一個的話,也是可以使用foreach循環(huán)的,只要刪除之后,立即結(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é)

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

相關(guān)文章

  • SpringBoot部署到外部Tomcat無法注冊到Nacos服務(wù)端的解決思路

    SpringBoot部署到外部Tomcat無法注冊到Nacos服務(wù)端的解決思路

    這篇文章主要介紹了SpringBoot部署到外部Tomcat無法注冊到Nacos服務(wù)端,本文給大家分享完美解決思路,結(jié)合實例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • java打印國際象棋棋盤的方法

    java打印國際象棋棋盤的方法

    這篇文章主要為大家詳細(xì)介紹了java打印出國際象棋棋盤的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • 使用idea搭建一個spring mvc項目的圖文教程

    使用idea搭建一個spring mvc項目的圖文教程

    這篇文章主要介紹了使用idea直接創(chuàng)建一個spring mvc項目的圖文教程,本文通過圖文并茂的方式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • 詳解Java中格式化日期的DateFormat與SimpleDateFormat類

    詳解Java中格式化日期的DateFormat與SimpleDateFormat類

    DateFormat其本身是一個抽象類,SimpleDateFormat 類是DateFormat類的子類,一般情況下來講DateFormat類很少會直接使用,而都使用SimpleDateFormat類完成,下面我們具體來看一下兩個類的用法:
    2016-05-05
  • Java中的移位運算符使用及原理詳解

    Java中的移位運算符使用及原理詳解

    在 Java 中,移位運算符用于對二進(jìn)制數(shù)進(jìn)行位移操作,它們可以將一個數(shù)的所有位向左或向右移動指定的位數(shù),本文小編將給大家詳細(xì)的介紹一下Java移位運算符,需要的朋友可以參考下
    2023-09-09
  • java中如何判斷對象是否是垃圾

    java中如何判斷對象是否是垃圾

    這篇文章主要介紹了java中如何判斷對象是否是垃圾,Java有兩種算法判斷對象是否是垃圾:引用計數(shù)算法和可達(dá)性分析算法,需要的朋友可以參考下
    2023-04-04
  • Java判斷閏年的2種方法示例

    Java判斷閏年的2種方法示例

    這篇文章主要給大家介紹了關(guān)于Java判斷閏年的2種方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 深入解析Jdk8中Stream流的使用讓你脫離for循環(huán)

    深入解析Jdk8中Stream流的使用讓你脫離for循環(huán)

    這篇文章主要介紹了Jdk8中Stream流的使用,讓你脫離for循環(huán),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • springboot+gradle 構(gòu)建多模塊項目的步驟

    springboot+gradle 構(gòu)建多模塊項目的步驟

    這篇文章主要介紹了springboot+gradle 構(gòu)建多模塊項目的步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java設(shè)計模式之職責(zé)鏈模式詳解

    Java設(shè)計模式之職責(zé)鏈模式詳解

    Java設(shè)計模式中有很多種類別,例如單例模式、裝飾模式、觀察者模式等。本文將為大家詳細(xì)介紹其中的職責(zé)鏈模式,感興趣的可以了解一下
    2021-12-12

最新評論