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

Java集合包中的fail fast機(jī)制詳解

 更新時(shí)間:2023年12月15日 09:39:47   作者:愛(ài)喝咖啡的程序員  
這篇文章主要介紹了Java集合包中的fail fast機(jī)制詳解,當(dāng)我們使用iterator迭代器遍歷一個(gè)集合的過(guò)程中,如果其它線(xiàn)程,或者它自己向這個(gè)集合新增或刪除了一個(gè)key-value,那么當(dāng)前線(xiàn)程就會(huì)拋出ConcurrentModificationException異常,需要的朋友可以參考下

Java的fail fast機(jī)制

首先說(shuō)說(shuō)現(xiàn)象,當(dāng)我們使用iterator迭代器遍歷一個(gè)集合的過(guò)程中,如果其它線(xiàn)程,或者它自己向這個(gè)集合新增或刪除了一個(gè)key-value,那么當(dāng)前線(xiàn)程就會(huì)拋出ConcurrentModificationException異常。

然后說(shuō)說(shuō)原理。無(wú)論是AbstractList,還是HashMap,它們都擁有一個(gè)modCount變量,每當(dāng)我們向集合新增或者刪除元素,都會(huì)使modCount的值增加1,這個(gè)參數(shù)就好像集合的操作版本號(hào)。當(dāng)我們?cè)诘?,?huì)創(chuàng)建一個(gè)expectedModCount,記錄了迭代之前的操作版本號(hào),每次迭代獲取數(shù)據(jù)時(shí),都會(huì)檢查一下,當(dāng)前的modCount是否與expectedModCount想等,若不相等,則說(shuō)明在當(dāng)前線(xiàn)程迭代遍歷元素時(shí),有其他的線(xiàn)程操作了集合。

集合包下面的集合都不是線(xiàn)程安全的,都會(huì)有并發(fā)問(wèn)題,所以都包含modCount變量。使用fail fast機(jī)制,當(dāng)一個(gè)線(xiàn)程在迭代遍歷,另一個(gè)線(xiàn)程在新增、刪除元素時(shí),就會(huì)立刻報(bào)錯(cuò)。

注意: 一個(gè)線(xiàn)程在迭代遍歷,另一個(gè)線(xiàn)程在修改元素時(shí),并不會(huì)觸發(fā)fail fast。可以看ArrayList和LinkedList的set()源碼,沒(méi)有發(fā)現(xiàn)modCount的痕跡(你只要不刪除,或者新增元素,就沒(méi)問(wèn)題)。

并且,fail fast僅僅是一個(gè)錯(cuò)誤檢測(cè)機(jī)制,因?yàn)镴DK并不能保證fail fast一定會(huì)發(fā)生。若在多線(xiàn)程環(huán)境下使用fail-fast機(jī)制的集合,建議使用“java.util.concurrent包下的類(lèi)”去取代“java.util包下的類(lèi)”。

口說(shuō)無(wú)憑,我們來(lái)看看源碼。就拿LinkedList來(lái)舉例,代碼如下所示:

LinkedList<String> list = new LinkedList<>();
list.add("123");
list.add("456");
list.add("789");
for (String str : list) {
	list.remove();
}

首次執(zhí)行l(wèi)ist.remove()是不會(huì)報(bào)錯(cuò)的,但是當(dāng)進(jìn)入下一輪循環(huán)時(shí),就會(huì)報(bào)錯(cuò)。

當(dāng)我們使用for循環(huán)遍歷任何一個(gè)List之前,底層都會(huì)調(diào)用listIterator( )方法,創(chuàng)建一個(gè)ListIterator對(duì)象,用于遍歷。LinkedList也不例外,它重寫(xiě)了listIterator()方法,返回了一個(gè)自定義的ListItr對(duì)象。

public ListIterator<E> listIterator(int index) {
	checkPositionIndex(index);
	return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
	// 省略..
	private int expectedModCount = modCount;
	ListItr(int index) {
		省略..
	}
	public E next() {
		checkForComodification();
		省略..
	}
	final void checkForComodification() {
		if (modCount != expectedModCount)
			throw new ConcurrentModificationException();
	}
}

我省略了許多與本文無(wú)關(guān)的代碼,關(guān)鍵代碼就那么幾句。執(zhí)行l(wèi)istIerator()方法時(shí),一定會(huì)創(chuàng)建一個(gè)ListItr對(duì)象,同時(shí)一定會(huì)初始化它的成員變量expectedModCount,等于當(dāng)前的modCount。

接下來(lái)就是遍歷,遍歷無(wú)非就是獲取List中的下一個(gè)元素,用屁股想想,調(diào)用的不就是next()方法么,next()方法一上來(lái)就執(zhí)行了checkForComodification(),比較一下當(dāng)前的modCount是否與expectedModCount一樣,如果不一樣,就拋出異常。

這個(gè)意思不就是在說(shuō),如果在遍歷List的過(guò)程中,你敢做新增或者刪除操作(累加了modCount的值),那就會(huì)報(bào)錯(cuò)。

值得注意的是,報(bào)錯(cuò)的地方不是list.remove(),報(bào)錯(cuò)的是你做了新增、刪除操作后的接下來(lái)的一輪遍歷時(shí),獲取數(shù)據(jù)時(shí)會(huì)報(bào)錯(cuò)。

那是不是只要遍歷集合時(shí),新增或者刪除(或者其它改變modCount的操作),都會(huì)報(bào)錯(cuò)呢?

不是的,只要你在查詢(xún)數(shù)據(jù)的時(shí)候,繞開(kāi)包含了modCount檢查的方法,就不會(huì)報(bào)錯(cuò)。

String str;
while((str = list.peekFirst()) != null) {
	System.out.println(str);
	list.pop();
}

上面的代碼也是在遍歷鏈表,但是不會(huì)報(bào)錯(cuò),因?yàn)閘ist.pop()沒(méi)有修改modCount的值,peekFirst()也沒(méi)有去檢查modCount,fail fast不復(fù)存在,就不會(huì)報(bào)錯(cuò)。

到此這篇關(guān)于Java集合包中的fail fast機(jī)制詳解的文章就介紹到這了,更多相關(guān)Java的fail fast機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis自定義攔截器實(shí)現(xiàn)權(quán)限功能

    Mybatis自定義攔截器實(shí)現(xiàn)權(quán)限功能

    本文主要介紹了Mybatis自定義攔截器實(shí)現(xiàn)權(quán)限功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼

    Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼

    MyBatis是一個(gè)支持普通SQL查詢(xún),存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架,下面給大家介紹Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼,非常不錯(cuò),感興趣的朋友一起看下吧
    2016-07-07
  • java編程實(shí)現(xiàn)求解八枚銀幣代碼分享

    java編程實(shí)現(xiàn)求解八枚銀幣代碼分享

    這篇文章主要介紹了java編程實(shí)現(xiàn)求解八枚銀幣代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Java如何通過(guò)線(xiàn)程解決生產(chǎn)者/消費(fèi)者問(wèn)題

    Java如何通過(guò)線(xiàn)程解決生產(chǎn)者/消費(fèi)者問(wèn)題

    這篇文章主要介紹了Java如何通過(guò)線(xiàn)程解決生產(chǎn)者/消費(fèi)者問(wèn)題,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-10-10
  • 從log4j切換到logback后項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題及解決方法

    從log4j切換到logback后項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題及解決方法

    這篇文章主要介紹了從log4j切換到logback后項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • Java中數(shù)組越界異常的優(yōu)雅解決方式

    Java中數(shù)組越界異常的優(yōu)雅解決方式

    ?數(shù)組越界報(bào)錯(cuò)通常發(fā)生在嘗試訪(fǎng)問(wèn)數(shù)組中不存在的索引時(shí),這可能導(dǎo)致程序崩潰或異常,這篇文章主要給大家介紹了關(guān)于Java中數(shù)組越界異常的優(yōu)雅解決方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Spring Boot修改啟動(dòng)端口的方法

    Spring Boot修改啟動(dòng)端口的方法

    下面小編就為大家?guī)?lái)一篇Spring Boot修改啟動(dòng)端口的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Java線(xiàn)程變量ThreadLocal源碼分析

    Java線(xiàn)程變量ThreadLocal源碼分析

    ThreadLocal用來(lái)提供線(xiàn)程內(nèi)部的局部變量,不同的線(xiàn)程之間不會(huì)相互干擾,這種變量在多線(xiàn)程環(huán)境下訪(fǎng)問(wèn)時(shí)能保證各個(gè)線(xiàn)程的變量相對(duì)獨(dú)立于其他線(xiàn)程內(nèi)的變量,在線(xiàn)程的生命周期內(nèi)起作用,可以減少同一個(gè)線(xiàn)程內(nèi)多個(gè)函數(shù)或組件之間一些公共變量傳遞的復(fù)雜度
    2022-08-08
  • Mybatis的入門(mén)示例代碼

    Mybatis的入門(mén)示例代碼

    首先新建一個(gè)JavaWeb項(xiàng)目并導(dǎo)入mybatis依賴(lài)的jar包,同時(shí)Mybatis是對(duì)數(shù)據(jù)庫(kù)的操作所以我們需要在數(shù)據(jù)庫(kù)中新建一個(gè)表user用來(lái)演示。下面通過(guò)本文給大家詳細(xì)介紹Mybatis的入門(mén)示例代碼,感興趣的朋友一起看看吧
    2016-11-11
  • springboot如何配置嵌套map和list參數(shù)

    springboot如何配置嵌套map和list參數(shù)

    這篇文章主要介紹了springboot如何配置嵌套map和list參數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評(píng)論