快速失败原理

        一般面试都有一些线程题目,大致是某某集合和某某集合什么区别,比如Hashmap .HashTable,ConcurrentHashMap有什么区别

很多网上答案都说线程安全,一个线程不安全。那么这里不是讨论什么叫线程安全,只是讨论线程不安全怎么办。

以HashMap为例,它不安全,什么叫不安全。简单理解就是多线程读写可能是脏数据,比如你在A线程读,B线程写了一个新数据,而

A线程却不知道。可怕。。

       之前有一个奔溃是java.util.ConcurrentModificationException,就是线程不安全的操作,不过更专业的说法是快速失败。HashMap在读的

过程中,如果写操作,jdk在处理这种情况是有一个判断的:

即迭代器迭代,检测当前集合大小,如果大小不符合预期则抛出异常达到快速失败的效果。

例如迭代器迭代开始时候是4个key,中间发现变成5个key,这时候迭代器直接失败抛出异常,因为

它认为迭代中是读操作,至始至终都应该是不变的集合才能保障效果。


这里有一些问题需要解释:

1.迭代过程,修改key对应的键值对,那也是修改了,那迭代要不要抛异常。如果抛异常怎么判断?毕竟集合大小没有变化



开启阅读源码模式

-----会奔溃的代码。

public static void main(String args[]) {
HashMap<String, String> map = new HashMap();
map.put("0", "1");
map.put("1", "x");
map.put("2", "x");
Iterator<String> i = map.keySet().iterator();
while (i.hasNext()) {
if (map.get(i.next()).equals("x")) {
map.put("ok", "true");
}
}
}

-------结束,那么问题应该是i.hasNext()

------jump it.read the fuck code

i是hashmap的键对应迭代器,简单介绍一下背景,这里是HashMap$KeySet,对应就是这里的内部类实现的迭代器

private final class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return newKeyIterator();
        }

||

V

 Iterator<K> newKeyIterator()   {
        return new KeyIterator();
    }

||

V

原来就是KeyIterator类了。

 private final class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

||

V

 final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();


            if ((next = e.next) == null) {
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
            current = e;
            return e;
        }


-----关键代码就是第一步的判断,也就是希望值和实际值不符合直接抛异常,这不就是生活中不符合预期直接解雇你吗。哈哈哈哈哈哈h

if (modCount != expectedModCount)
                throw new ConcurrentModificationException();


小情绪梳理一下,HashMap迭代器中,每一次迭代都判断当前梳理和预期梳理是不是符合保持一致,如果不一致不再迭代直接抛异常。

那么再解释一下几个变量的原理

modCount != expectedModCount

 /**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     */
    transient int modCount;
HashMap结构修改的次数,包括那些修改Hashmap映射的数量或者导致内部结构

变化的数量,这个变量是用于快速失败


就是这么理解呗,hashmap变化就将变量+1

常见的是不是有put操作,remove操作,

看看



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值