成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

快速失敗(fail-fast)與安全失敗(fail-safe)

imtianx / 1271人閱讀

摘要:注意,迭代器的快速失敗行為無法得到保證,因?yàn)橐话銇碚f,不可能對(duì)是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證??焖偈〉鲿?huì)盡最大努力拋出。

fail-fast與fail-safe

在Collection集合的各個(gè)類中,有線程安全和線程不安全這2大類的版本。

對(duì)于線程不安全的類,并發(fā)情況下可能會(huì)出現(xiàn)fail-fast情況;而線程安全的類,可能出現(xiàn)fail-safe的情況。

一、并發(fā)修改

當(dāng)一個(gè)或多個(gè)線程正在遍歷一個(gè)集合Collection的時(shí)候(Iterator遍歷),而此時(shí)另一個(gè)線程修改了這個(gè)集合的內(nèi)容(如添加,刪除或者修改)。這就是并發(fā)修改的情況。

二、fail-fast快速失敗

fail-fast機(jī)制:當(dāng)遍歷一個(gè)集合對(duì)象時(shí),如果集合對(duì)象的結(jié)構(gòu)被修改了,就會(huì)拋出ConcurrentModificationExcetion異常。

有2種情況會(huì)拋出該異常:

在單線程的情況下,如果使用Iterator對(duì)象遍歷集合對(duì)象的過程中,修改了集合對(duì)象的結(jié)構(gòu)。如下:

// 1.iterator迭代,拋出ConcurrentModificationException異常
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
  String s = iterator.next();
  System.out.println(s);
  // 修改集合結(jié)構(gòu)
  if ("s2".equals(s)) {
    list.remove(s);
  }
}

// 2.foreach迭代,拋出ConcurrentModificationException異常
for (String s : list) {
  System.out.println(s);
  // 修改集合結(jié)構(gòu)
  if ("s2".equals(s)) {
    list.remove(s);
  }
}

要想避免拋出異常,應(yīng)該使用Iterator對(duì)象的remove()方法。

// 3.iterator迭代,使用iterator.remove()移除元素不會(huì)拋出異常
Iterator iterator2 = list.iterator();
while (iterator2.hasNext()) {
  String s = iterator2.next();
  System.out.println(s);
  // 修改集合結(jié)構(gòu)
  if ("s2".equals(s)) {
  iterator2.remove();
  }
}

在多線程環(huán)境下,如果對(duì)集合對(duì)象進(jìn)行并發(fā)修改,那么就會(huì)拋出ConcurrentModificationException異常。

注意,迭代器的快速失敗行為無法得到保證,因?yàn)橐话銇碚f,不可能對(duì)是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證。快速失敗迭代器會(huì)盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個(gè)依賴于此異常的程序是錯(cuò)誤的做法,迭代器的快速失敗行為應(yīng)該僅用于檢測 bug。

以ArrayList為例,講解一下fail-fast的機(jī)制 1、單線程下,使用iterator迭代時(shí)的情況

ArrayList繼承自AbstractList類,AbstractList內(nèi)部有一個(gè)字段modCount,代表修改的次數(shù)。

ArrayList類的add、remove操作都會(huì)使得modCount自增。

當(dāng)使用ArrayList.iterator()返回一個(gè)迭代器對(duì)象時(shí)。迭代器對(duì)象有一個(gè)屬性expectedModCount,它被賦值為該方法調(diào)用時(shí)modCount的值。這意味著,這個(gè)值是modCount在這個(gè)時(shí)間點(diǎn)的快照值,expectedModCount值在iterator對(duì)象內(nèi)部不會(huì)再發(fā)送變化!

這時(shí)候我們就能明白了,在得到迭代器之后,如果我們使用ArrayList的add、remove等方法,會(huì)使得modCount的值自增(發(fā)生了變化),而iterator內(nèi)部的expectedModCount值卻還是之前的快照值。我們再來看iterator的方法實(shí)現(xiàn):可以看到,在調(diào)用next方法時(shí),第一步就是檢查modCount值和迭代器內(nèi)部的expectedModCount值是否相等!顯然,這是不等的,所以在調(diào)用next方法的時(shí)候,就拋出了ConcurrentModificationException異常。

為什么說迭代器的fail-fast機(jī)制是盡最大努力地拋出ConcurrentModificationException異常呢?

原因就是上面我們看到的,只有在迭代過程中修改了元素的結(jié)構(gòu),當(dāng)再調(diào)用next()方法時(shí)才會(huì)拋出該異常。也就是說,如果迭代過程中發(fā)生了修改,但之后沒有調(diào)用next()迭代,該異常就不會(huì)拋出了!(該異常的機(jī)制是告訴你,當(dāng)前迭代器要進(jìn)行操作是有問題的,因?yàn)?strong>集合對(duì)象現(xiàn)在的狀態(tài)發(fā)生了改變?。?/p>

那為什么iterator.remove()方法可行呢?

下圖中,可以看到,remove方法沒有進(jìn)行modCount值的檢查,并且手動(dòng)把expectedModCount值修改成了modCount值,這又保證了下一次迭代的正確。

2、多線程下的情況

當(dāng)然,如果多線程下使用迭代器也會(huì)拋出ConcurrentModificationException異常。而如果不進(jìn)行迭代遍歷,而是并發(fā)修改集合類,則可能會(huì)出現(xiàn)其他的異常如數(shù)組越界異常。

三、fail-safe安全失敗

Fail-Safe 迭代的出現(xiàn),是為了解決fail-fast拋出異常處理不方便的情況。fail-safe是針對(duì)線程安全的集合類。

上面的fail-fast發(fā)生時(shí),程序會(huì)拋出異常,而fail-safe是一個(gè)概念,并發(fā)容器的并發(fā)修改不會(huì)拋出異常,這和其實(shí)現(xiàn)有關(guān)。并發(fā)容器的iterate方法返回的iterator對(duì)象,內(nèi)部都是保存了該集合對(duì)象的一個(gè)快照副本,并且沒有modCount等數(shù)值做檢查。如下圖,這也造成了并發(fā)容器的iterator讀取的數(shù)據(jù)是某個(gè)時(shí)間點(diǎn)的快照版本。你可以并發(fā)讀取,不會(huì)拋出異常,但是不保證你遍歷讀取的值和當(dāng)前集合對(duì)象的狀態(tài)是一致的!這就是安全失敗的含義。

所以Fail-Safe 迭代的缺點(diǎn)是:首先是iterator不能保證返回集合更新后的數(shù)據(jù),因?yàn)槠涔ぷ髟诩峡寺∩?,而非集合本身。其次,?chuàng)建集合拷貝需要相應(yīng)的開銷,包括時(shí)間和內(nèi)存。

在java.util.concurrent 包中集合的迭代器,如 ConcurrentHashMap, CopyOnWriteArrayList等默認(rèn)為都是Fail-Safe。

// 1.foreach迭代,fail-safe,不會(huì)拋出異常
for (String s : list) {
  System.out.println(s);
  if ("s1".equals(s)) {
  list.remove(s);
  }
}

// 2.iterator迭代,fail-safe,不會(huì)拋出異常
Iterator iterator = list.iterator();
  while (iterator.hasNext()) {
  String s = iterator.next();
  System.out.println(s);
  if ("s1".equals(s)) {
  list.remove(s);
  }
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/71683.html

相關(guān)文章

  • fail-fastfail-safe

    摘要:一什么是機(jī)制在用迭代器遍歷集合時(shí)當(dāng)集合的結(jié)構(gòu)被修改會(huì)拋出異常二什么情況下集合的結(jié)構(gòu)會(huì)被修改單線程環(huán)境集合在遍歷的過程中如果要對(duì)集合進(jìn)行增刪操作沒有調(diào)用迭代器的方法而是用的集合自身的方法則可能會(huì)產(chǎn)生事件多線程環(huán)境下當(dāng)一個(gè)線程在遍歷某個(gè)集合 一.什么是fail-fast機(jī)制? 在用迭代器遍歷集合時(shí),當(dāng)集合的結(jié)構(gòu)被修改,會(huì)拋出ConcurrentModificationException異常...

    魏明 評(píng)論0 收藏0
  • 面試官:說說快速失敗安全失敗是什么

    摘要:我們都接觸這些集合類,這些在包的集合類就都是快速失敗的而包下的類都是安全失敗,比如。安全失敗明白了什么是快速失敗之后,安全失敗也是非常好理解的。最后說明一下,快速失敗和安全失敗是對(duì)迭代器而言的。 什么是快速失敗(fail-fast)和安全失?。╢ail-safe)?它們又和什么內(nèi)容有關(guān)系。以上兩點(diǎn)就是這篇文章的內(nèi)容,廢話不多話,正文請(qǐng)慢用。 我們都接觸 HashMap、ArrayLis...

    calx 評(píng)論0 收藏0
  • fail-fastfail-safe在Java集合中的應(yīng)用

    摘要:與在迭代器中的設(shè)計(jì)在中,最典型的與就是關(guān)于迭代器的設(shè)計(jì)。缺點(diǎn)是,迭代器不能正確及時(shí)的反應(yīng)集合中的內(nèi)容,而且一定程度上也增加了內(nèi)存的消耗。 fail-fast與fail-safe簡介 如果一個(gè)系統(tǒng),當(dāng)有異常或者錯(cuò)誤發(fā)生時(shí)就立即中斷執(zhí)行,這種設(shè)計(jì)稱之為fail-fast。相反如果我們的系統(tǒng)可以在某種異?;蛘咤e(cuò)誤發(fā)生時(shí)繼續(xù)執(zhí)行,不會(huì)被中斷,這種設(shè)計(jì)稱之為fail-safe。 fail-fas...

    Drummor 評(píng)論0 收藏0
  • 帶你了解集合世界的fail-fast機(jī)制 和 CopyOnWriteArrayList 源碼詳解

    摘要:體現(xiàn)的就是適配器模式。數(shù)組對(duì)象集合世界中的機(jī)制機(jī)制集合世界中比較常見的錯(cuò)誤檢測機(jī)制,防止在對(duì)集合進(jìn)行遍歷過程當(dāng)中,出現(xiàn)意料之外的修改,會(huì)通過異常暴力的反應(yīng)出來。而在增強(qiáng)循環(huán)中,集合遍歷是通過進(jìn)行的。 前言 學(xué)習(xí)情況記錄 時(shí)間:week 2 SMART子目標(biāo) :Java 容器 記錄在學(xué)習(xí)Java容器 知識(shí)點(diǎn)中,關(guān)于List的重點(diǎn)知識(shí)點(diǎn)。 知識(shí)點(diǎn)概覽: 容器中的設(shè)計(jì)模式 從Array...

    young.li 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<