fail safe java_夜談 Java中 Fail-fast 和 Fail-safe 的原理與使用

Fail-fast 和 Fail-safe會涉及到Javaz中的一些術語。

首先得先了解並發修改。

1.什么是並發修改?

當一個或多個線程正在遍歷一個集合Collection,此時另一個線程修改了這個集合的內容(添加,刪除或者修改)。

這就是並發修改

2.什么是 fail-fast 機制?

fail-fast機制在遍歷一個集合時,當集合結構被修改,會拋出Concurrent Modification Exception。

fail-fast會在以下兩種情況下拋出ConcurrentModificationException

(1)單線程環境

集合被創建后,在遍歷它的過程中修改了結構。

注意 remove()方法會讓expectModcount和modcount 相等,所以是不會拋出這個異常。

(2)多線程環境

當一個線程在遍歷這個集合,而另一個線程對這個集合的結構進行了修改。

注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步並發修改做出任何硬性保證。快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個依賴於此異常的程序是錯誤的做法:迭代器的快速失敗行為應該僅用於檢測 bug。

3. fail-fast機制是如何檢測的?

迭代器在遍歷過程中是直接訪問內部數據的,因此內部的數據在遍歷的過程中無法被修改。為了保證不被修改,迭代器內部維護了一個標記 “mode” ,當集合結構改變(添加刪除或者修改),標記"mode"會被修改,而迭代器每次的hasNext()和next()方法都會檢查該"mode"是否被改變,當檢測到被修改時,拋出Concurrent Modification Exception

。下面看看ArrayList迭代器部分的源碼。

private class Itr implements Iterator {

int cursor;

int lastRet = -1;

int expectedModCount = ArrayList.this.modCount;

public boolean hasNext() {

return (this.cursor != ArrayList.this.size);

}

public E next() {

checkForComodification();

/** 省略此處代碼 */

}

public void remove() {

if (this.lastRet < 0)

throw new IllegalStateException();

checkForComodification();

/** 省略此處代碼 */

}

final void checkForComodification() {

if (ArrayList.this.modCount == this.expectedModCount)

return;

throw new ConcurrentModificationException();

}

}

可以看到它的標記“mode”為 expectedModeCount

4. fail-safe機制

fail-safe任何對集合結構的修改都會在一個復制的集合上進行修改,因此不會拋出ConcurrentModificationException

fail-safe機制有兩個問題

(1)需要復制集合,產生大量的無效對象,開銷大

(2)無法保證讀取的數據是目前原始數據結構中的數據。

5 fail-fast 和 fail-safe的例子

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

public class FailFastExample

{

public static void main(String[] args)

{

Map premiumPhone = new HashMap();

premiumPhone.put("Apple", "iPhone");

premiumPhone.put("HTC", "HTC one");

premiumPhone.put("Samsung","S5");

Iterator iterator = premiumPhone.keySet().iterator();

while (iterator.hasNext())

{

System.out.println(premiumPhone.get(iterator.next()));

premiumPhone.put("Sony", "Xperia Z");

}

}

}

輸出

iPhone

Exception in thread "main" java.util.ConcurrentModificationException

at java.util.HashMap$HashIterator.nextEntry(Unknown Source)

at java.util.HashMap$KeyIterator.next(Unknown Source)

at FailFastExample.main(FailFastExample.java:20)

import java.util.concurrent.ConcurrentHashMap;

import java.util.Iterator;

public class FailSafeExample

{

public static void main(String[] args)

{

ConcurrentHashMap premiumPhone =

new ConcurrentHashMap();

premiumPhone.put("Apple", "iPhone");

premiumPhone.put("HTC", "HTC one");

premiumPhone.put("Samsung","S5");

Iterator iterator = premiumPhone.keySet().iterator();

while (iterator.hasNext())

{

System.out.println(premiumPhone.get(iterator.next()));

premiumPhone.put("Sony", "Xperia Z");

}

}

}輸出

S5

HTC one

iPhoneIterator的安全失敗是基於對底層集合做拷貝,因此,它不受源集合上修改的影響。java.util包下面的所有的集合類都是快速失敗的,而java.util.concurrent包下面的所有的類都是安全失敗的。快速失敗的迭代器會拋出ConcurrentModificationException異常,而安全失敗的迭代器永遠不會拋出這樣的異常.

6. fail-fast和 fail-safe 的區別

Fail Fast Iterator

Fail Safe Iterator

Throw ConcurrentModification Exception

Yes

No

Clone object

No

Yes

Memory Overhead

No

Yes

Examples

HashMap,Vector,ArrayList,HashSet

CopyOnWriteArrayList,

ConcurrentHashMap

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值