99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

單線程是否會(huì)引起 fail-fast機(jī)制

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-10 16:31 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

fail-fast 是什么

引用百度百科的數(shù)據(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 事件。

多線程?并發(fā)修改?才會(huì)引起 fail-fast 機(jī)制保護(hù)程序?小 B 覺得這個(gè)答案沒有說全,面試官說了單線程也會(huì)引起 fail-fast 機(jī)制。那么關(guān)于單線程是否會(huì)引起 fail-fast 機(jī)制,百度百科說的對(duì)還是面試官說的對(duì),寫一個(gè) demo 就清楚了。

import java.util.ArrayList;
import java.util.List;

public class FastFailTest {

    public static void main(String[] args) {
        List< String > list = new ArrayList< String >();

        list.add("張三");
        list.add("李四");
        list.add("王五");
        list.add("趙六");

        for(String s : list) {
            if(s.equals("趙六")) {
                list.remove(s);
                System.out.println(list.toString());
            }
        }
    }
}

從下圖的運(yùn)行結(jié)果來看,list 已經(jīng)完成了對(duì) [趙六] 的 remove,說明并不是 remove 引發(fā)的問題,仔細(xì)查看異常原因:是在 ArrayList 的內(nèi)部 Itr.checkForComodification() 方法出現(xiàn)的 ConcurrentModificationException 異常。小 B 感概了一句:網(wǎng)上資料不可盡信,動(dòng)手實(shí)戰(zhàn)才能出真知。

圖片

原理

將異常定位到報(bào)錯(cuò)的 ArrayList.java:911 行。

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

可以看到這個(gè)方法 checkForComodification 對(duì) modCount 和 expectedModCount 進(jìn)行了比較,如果不相同就拋出異常。modCount 和 expectedModCount 分別又是什么呢?remove 方法中不是修改了 modCount 就是修改了 expectedModCount。

modCount 被定義在 ArrayList 的父類 AbstractList 中,每一次調(diào)用 Add、Remove、Clear 等方法 modCount 就被 +1,可以說明這個(gè)變量的作用就是記錄了 ArrayList 實(shí)際被修改的次數(shù)。

ArrayList 的 foreach 方法是用迭代器 Iterator 實(shí)現(xiàn)的,Iterator 在 ArrayList 中有一個(gè)實(shí)現(xiàn)類:Itr,它的成員變量 expectedModCount 在初始化的時(shí)候被賦值了 modCount。所以當(dāng) ArrayList 調(diào)用 remove 刪除元素時(shí),modCount 被 +1,此時(shí)不等于 expectedModCount,在 foreach 試圖將局部變量 s 交接給下一個(gè)元素的時(shí)候,就出現(xiàn)了 ConcurrentModificationException 異常。

圖片

避免

經(jīng)過分析,ConcurrentModificationException 是由于 modCount 和 expectedModCount 不一樣導(dǎo)致的。

那么如何避免在循環(huán)的時(shí)候 add、remove 元素不拋出異常呢?

for 循環(huán)

使用普通的 for 循環(huán),這樣就可以不經(jīng)過 Itr 內(nèi)部類了。

List< String > list = new ArrayList< String >();

list.add("張三");
list.add("李四");
list.add("王五");
list.add("趙六");

for( int i = 0; i < list.size(); i++) {
    String s = list.get(i);
    if(s.equals("王五")) {
        list.remove(s);
        System.out.println(list.toString());
    }
}

示例結(jié)果是 [張三, 李四, 趙六] 沒有出現(xiàn)異常。但是移除元素后面的索引已經(jīng)被改變了。

迭代器 Iterator

直接使用迭代器 Iterator 中的方法,在它的remove 方法中顯示的將 expectedModCount 賦值成 modCount。

//Itr.remove()
public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

定義一個(gè)迭代器局部變量,使用 hasNext() 方法控制 while 循環(huán)。

List< String > list = new ArrayList< String >();

list.add("張三");
list.add("李四");
list.add("王五");
list.add("趙六");

Iterator< String > iterator = list.iterator();
while (iterator.hasNext()) {
    String s = iterator.next();
    if(s.equals("王五")) {
        iterator.remove();
        System.out.println(list.toString());
    }
}

CopyOnWriteArrayList

CopyOnWriteArrayList 是 java 并發(fā)包 java.util.concurrent 下面的類。它在操作 add、remove 元素時(shí),先將原來的元素?cái)?shù)組拷貝一份成為新的數(shù)組,在新數(shù)組上面做元素操作,修改完成后,將 CopyOnWriteArrayList 中數(shù)組的引用指向了新數(shù)組。

List< String > list = new CopyOnWriteArrayList< String >();

list.add("張三");
list.add("李四");
list.add("王五");
list.add("趙六");

for(String s : list) {
    if(s.equals("李四")) {
        list.remove(s);
        System.out.println(list.toString());
    }
}

總結(jié)

fail-fast 機(jī)制就是不允許程序員不管是在單線程還是多線程環(huán)境中遍歷集合的時(shí)候順便還操作集合里面的元素。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2989

    瀏覽量

    109607
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3826

    瀏覽量

    82968
  • 單線程
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    1838
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    單線程的雙任務(wù)調(diào)度

    STM32是單線程的,通信協(xié)議層和應(yīng)用功能層的耦合性比較低,如果獨(dú)立運(yùn)行,提高效率不少,主要實(shí)現(xiàn)的方法有哪些呢?
    發(fā)表于 01-10 10:15

    單線程SRAM靜態(tài)內(nèi)存使用

    概述本篇只要介紹這么使用STM32CubeMx工具添加RT-Thread操作系統(tǒng)組件,碼代碼的IDE是keil。介紹單線程SRAM靜態(tài)內(nèi)存使用。如果還不知道,這么使用STM32CubeMx工具添加
    發(fā)表于 08-24 06:57

    一種單線程編程思路簡析

    事件驅(qū)動(dòng)?邏輯控制?基于回調(diào)的事件驅(qū)動(dòng)或者邏輯控制特點(diǎn)代碼接口實(shí)現(xiàn)用法基于回調(diào)的事件驅(qū)動(dòng)或者邏輯控制本文提供了一種單線程編程思路,并簡單實(shí)現(xiàn)了該思路。受PLC編程線圈和觸點(diǎn)概念的啟發(fā)。將程序抽象理解
    發(fā)表于 02-16 06:58

    LabWindows_CVI多線程技術(shù)的應(yīng)用研究

    分析了線程與進(jìn)程的關(guān)系,研究了LabWindows/CVI多線程技術(shù)運(yùn)行機(jī)制及其數(shù)據(jù)保護(hù)機(jī)制,對(duì)利用異步定時(shí)器實(shí)現(xiàn)的多線程軟件與傳統(tǒng)
    發(fā)表于 08-29 14:53 ?68次下載
    LabWindows_CVI多<b class='flag-5'>線程</b>技術(shù)的應(yīng)用研究

    線程好還是單線程好?單線程和多線程的區(qū)別 優(yōu)缺點(diǎn)分析

    摘要:如今單線程與多線程已經(jīng)得到普遍運(yùn)用,那么到底多線程好還是單線程好呢?單線程和多線程的區(qū)別又
    發(fā)表于 12-08 09:33 ?8.2w次閱讀

    從I/O的阻塞與非阻塞、I/O處理的單線程與多線程角度探討服務(wù)器模型

    這里探討的服務(wù)器模型主要指的是服務(wù)器端對(duì)I/O的處理模型。從不同維度可以有不同的分類,這里從I/O的阻塞與非阻塞、I/O處理的單線程與多線程角度探討服務(wù)器模型。
    的頭像 發(fā)表于 01-08 16:13 ?7329次閱讀

    Intel處理器占據(jù)CPU單線程性能前17位 酷睿i9-9900KS仍穩(wěn)居榜首

    目前,PassMark的CPU單線程性能圖表仍然由Intel芯片主導(dǎo)。在AMD的Ryzen 9 PRO 3900前面,總共有17個(gè)Intel處理器占據(jù)了主導(dǎo)地位。
    發(fā)表于 04-09 14:39 ?2996次閱讀
    Intel處理器占據(jù)CPU<b class='flag-5'>單線程</b>性能前17位 酷睿i9-9900KS仍穩(wěn)居榜首

    實(shí)現(xiàn)Java多線程爬蟲的兩點(diǎn)

    在我們調(diào)試爬蟲程序的時(shí)候,單線程爬蟲沒什么問題,但是當(dāng)我們?cè)诰€上環(huán)境使用單線程爬蟲程序去采集網(wǎng)頁時(shí),單線程就暴露出了兩個(gè)致命的問題:
    的頭像 發(fā)表于 05-05 21:25 ?2163次閱讀
    實(shí)現(xiàn)Java多<b class='flag-5'>線程</b>爬蟲的兩點(diǎn)

    這款16核怪物在單線程和多線程性能方面均躍居主流處理器榜首

    盡管AMD一段時(shí)間以來一直在主流芯片中注入更多的內(nèi)核,但在單線程性能方面,這家芯片制造商的產(chǎn)品還不能與Intel的產(chǎn)品相提并論。如果這些PassMark號(hào)碼準(zhǔn)確無誤,那么Zen 3似乎終于可以輕而易舉地獲得AMD的青睞。
    的頭像 發(fā)表于 10-28 15:24 ?2350次閱讀

    單線程也能開發(fā)異步任務(wù)?ACE JS框架到底是如何做到的

    ,用JS語言開發(fā)是否會(huì)導(dǎo)致硬件資源無法充分利用的情況呢? 本文給大家介紹“ACE JS的單線程異步機(jī)制”就是解決這個(gè)問題的。然而,說到 “單線程”與“異步”,大家可能會(huì)比較疑惑,因?yàn)?/div>
    的頭像 發(fā)表于 08-13 17:16 ?2388次閱讀
    <b class='flag-5'>單線程</b>也能開發(fā)異步任務(wù)?ACE JS框架到底是如何做到的

    JVM的垃圾機(jī)制是如何工作的呢?

    單線程收集器,“單線程” 的意義并不僅僅說明它只會(huì)使用一個(gè) CPU 或一條收集線程去完成垃圾收集工作,更重要的是在它進(jìn)行垃圾收集時(shí),必須暫停其他所有的工作線程 , 直到它收集結(jié)束。
    的頭像 發(fā)表于 02-28 16:08 ?851次閱讀

    Redis為何選擇單線程

    Redis為何選擇單線程? 在Redisv6.0以前,Redis的核心網(wǎng)絡(luò)模型選擇用單線程來實(shí)現(xiàn)。 核心意思就是,對(duì)于一個(gè) DB 來說,CPU 通常不會(huì)是瓶頸,因?yàn)榇蠖鄶?shù)請(qǐng)求不會(huì)是 CPU 密集型
    的頭像 發(fā)表于 10-09 10:59 ?596次閱讀

    Go在單線程計(jì)算性能上的優(yōu)勢(shì)

    一文中,我們討論了Go在單線程計(jì)算性能上的優(yōu)勢(shì)。 現(xiàn)在,考慮這樣的一種場(chǎng)景: 我們需要從某些網(wǎng)址中同步數(shù)據(jù)并進(jìn)行計(jì)算,保存到本地redis緩存中。 現(xiàn)在,我們可以通過編寫Go Worker的方式
    的頭像 發(fā)表于 11-02 11:16 ?716次閱讀
    Go在<b class='flag-5'>單線程</b>計(jì)算性能上的優(yōu)勢(shì)

    redis多線程還能保證線程安全嗎

    Redis是一種使用C語言編寫的高性能鍵值存儲(chǔ)系統(tǒng),它是單線程的,因?yàn)槭褂昧硕嗦窂?fù)用的方式來處理并發(fā)請(qǐng)求。這樣的實(shí)現(xiàn)方式帶來了很好的性能,但同時(shí)也引發(fā)了一些線程安全方面的問題。 在Redis中,由于
    的頭像 發(fā)表于 12-05 10:28 ?2259次閱讀

    什么是多核多線程?多核多線程如何提高程序的運(yùn)行效率?

    單線程無法充分利用多核處理器的并行計(jì)算能力。
    的頭像 發(fā)表于 02-20 10:22 ?2047次閱讀