百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

关于Java集合中fail-fast(快速失败)机制的相关资料

suiw9 2024-11-17 15:50 45 浏览 0 评论

这篇文章主要给大家介绍了关于Java集合中fail-fast(快速失败)机制的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

简介

我们知道Java中Collection接口下的很多集合都是线程不安全的, 比如 java.util.ArrayList不是线程安全的, 因此如果在使用迭代器的过程中有其他线程修改了list,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 list
注意到 modCount 声明为 volatile,保证线程之间修改的可见性。

modCount和expectedModCount

modCount和expectedModCount是用于表示修改次数的,其中modCount表示集合的修改次数,这其中包括了调用集合本身的add, remove, clear方法等修改方法时进行的修改和调用集合迭代器的修改方法进行的修改。而expectedModCount则是表示迭代器对集合进行修改的次数。

设置expectedModCount的目的就是要保证在使用迭代器期间,list对象只能有这一个迭代器对list进行修改。

在创建迭代器的时候会把对象的modCount的值传递给迭代器的expectedModCount:


private class ListItr implements ListIterator<E> {

private Node<E> lastReturned;

private Node<E> next;

private int nextIndex;

private int expectedModCount = modCount;

如果创建多个迭代器对一个集合对象进行修改的话,那么就会有一个modCount和多个expectedModCount,且modCount的值之间也会不一样,这就导致了moCount和expectedModCount的值不一致,从而产生异常:


public E next() {

checkForComodification();

if (!hasNext())

throw new NoSuchElementException();


lastReturned = next;

next = next.next;

nextIndex++;

return lastReturned.item;

}


上面的代码中的checkForComodification会检查modCount和expectedModCount的值是否一致,不一致则抛出异常。


final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();



modCount是如何被修改的


// 添加元素到队列最后

public boolean add(E e) {

// 修改modCount

ensureCapacity(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}



// 添加元素到指定的位置

public void add(int index, E element) {

if (index > size || index < 0)

throw new IndexOutOfBoundsException(

"Index: "+index+", Size: "+size);


// 修改modCount

ensureCapacity(size+1); // Increments modCount!!

System.arraycopy(elementData, index, elementData, index + 1,

size - index);

elementData[index] = element;

size++;

}


// 添加集合

public boolean addAll(Collection<? extends E> c) {

Object[] a = c.toArray();

int numNew = a.length;

// 修改modCount

ensureCapacity(size + numNew); // Increments modCount

System.arraycopy(a, 0, elementData, size, numNew);

size += numNew;

return numNew != 0;

}



// 删除指定位置的元素

public E remove(int index) {

RangeCheck(index);


// 修改modCount

modCount++;

E oldValue = (E) elementData[index];


int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index, numMoved);

elementData[--size] = null; // Let gc do its work


return oldValue;

}



// 快速删除指定位置的元素

private void fastRemove(int index) {


// 修改modCount

modCount++;

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null; // Let gc do its work

}


// 清空集合

public void clear() {

// 修改modCount

modCount++;


// Let gc do its work

for (int i = 0; i < size; i++)

elementData[i] = null;


size = 0;

}



也就是在对集合进行数据的增删的时候都会执行modcount++, 那么如果一个线程还在使用迭代器遍历这个list的时候就会发现异常, 发生 fail-fast(快速失败)

fail-fast(快速失败)和fail-safe(安全失败)比较

Iterator的快速失败是基于对底层集合做拷贝是浅拷贝,因此,它受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的

而java.util.concurrent包下面的所有的类都是使用锁实现安全失败的。

快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。

fail-fast解决什么问题

fail-fast机制,是一种错误检测机制。

它只能被用来检测错误,因为JDK并不保证fail-fast机制一定会发生。只是在多线程环境下告诉客户端发生了多线程安全问题.
所以若在多线程环境下使用fail-fast机制的集合,建议使用“java.util.concurrent包下的类”去取代“java.util包下的类”。

如何解决fail-fast事件

ArrayList对应的CopyOnWriteArrayList进行说明。我们先看看CopyOnWriteArrayList的源码:


public class CopyOnWriteArrayList<E>

implements List<E>, RandomAccess, Cloneable, java.io.Serializable {


...


// 返回集合对应的迭代器

public Iterator<E> iterator() {

return new COWIterator<E>(getArray(), 0);

}


...


private static class COWIterator<E> implements ListIterator<E> {

private final Object[] snapshot;


private int cursor;


private COWIterator(Object[] elements, int initialCursor) {

cursor = initialCursor;

// 新建COWIterator时,将集合中的元素保存到一个新的拷贝数组中。

// 这样,当原始集合的数据改变,拷贝数据中的值也不会变化。

snapshot = elements;

}


public boolean hasNext() {

return cursor < snapshot.length;

}


CopyOnWriteArrayList是自己实现Iterator, 并且CopyOnWriteArrayList的Iterator实现类中,没有所谓的checkForComodification(),更不会抛出ConcurrentModificationException异常

CopyOnWriteArrayList在进行新建COWIterator时,将集合中的元素保存到一个新的拷贝数组中。这样,当原始集合的数据改变,拷贝数据中的值也不会变化。

相关推荐

俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)

发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...

如何强制所有流量使用 HTTPS一网上用户

如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...

https和http的区别(https和http有何区别)

“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...

快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别

什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...

简述HTTPS工作原理(简述https原理,以及与http的区别)

https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...

21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)

HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...

一次安全可靠的通信——HTTPS原理

为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...

为什么有的网站没有使用https(为什么有的网站点不开)

有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...

HTTPS是什么?加密原理和证书。SSL/TLS握手过程

秘钥的产生过程非对称加密...

图解HTTPS「转」(图解http 完整版 彩色版 pdf)

我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...

HTTP 和 HTTPS 有何不同?一文带你全面了解

随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...

HTTP与HTTPS的区别,详细介绍(http与https有什么区别)

HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...

一文让你轻松掌握 HTTPS(https详解)

一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...

如何在Spring Boot应用程序上启用HTTPS?

HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...

一文彻底搞明白Http以及Https(http0)

早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...

取消回复欢迎 发表评论: