8.互联网大厂高频面试题-arraylist线程不安全

集合类不安全之并发修改异常

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
新建对象的过程中,底层新建了一个初始大小为10的obj数组。
在这里插入图片描述
size是数组里面的元素。
在这里插入图片描述
在这里插入图片描述
add方法的源码:
在这里插入图片描述
添加的时候先确认内部空间,让其加一。函数源码如下:
在这里插入图片描述
如果是默认的数组,没写大小,内部空间就是10,minCapacity是size,size是全局变量,jvm赋初始值0,加一之后就是1。default_capacity是全局静态变量,如下:
在这里插入图片描述
如果增加到了一定程度,需要通过ensureExplicitcapacity方法扩容。
在这里插入图片描述
扩充原来长度的一半。
在这里插入图片描述
arraylist线程不安全的例子,写一个。以add方法为例,演示线程不安全,因为add方法的源代码没有加锁。

在这里插入图片描述
结果2:
在这里插入图片描述
数量上不对了,内容上不对了,但是,没有报错!
线程改为30个之后,出现了经典的并发修改问题:
在这里插入图片描述
发生了JUC的并发修改异常,这是做并发项目经常遇到的。
作为一个程序员,解决问题的框架是4步:
在这里插入图片描述
发现故障现象,分析导致原因,提出解决方案,总结最佳实践(优化建议)。
故障现象就是那个异常了,导致原因就是arraylist不能支持并发,会有多线程的安全问题。
建立自己的故障笔记。只会撸代码走不远。天下武艺,没有高低之分,只有习武之人,有强弱之别。
arraylist没有加sync同步关键字,报了这个错,换成线程安全的vector,它的add方法加了sync关键字,结果就是:
在这里插入图片描述
没有出现异常。但是加锁,会让并发性急剧下降!
arraylist是jdk1.2版本出现的,vector是1.1版本。
我们可以提出方案是vector解决,就不会报异常了,但是不是最佳实践。
可以使用Collections包装类,来包装list为同步的,兼容并发。
在这里插入图片描述
也是可以解决的,这是方案二,但是底层还是加了sync关键字。性能下降是硬伤。
在这里插入图片描述

在这里插入图片描述

方案三:copyOnWriteArrayList,俗称写时复制。
在这里插入图片描述
先看运行效果,是可以解决问题的。
在这里插入图片描述
到此,不要只是会用,要明白底层原理!
笔试,过关说明你没有丧失学习能力,不一定能直接干活!
底层解析:
在这里插入图片描述

存储数据的数组是volatile修饰的,线程可见,禁止重排。在高并发场景里面,重要的核心变量都需要加volatile。
add方法解析:
在这里插入图片描述
源代码加了可重入锁(reentrantlock),先对原先的数组进行赋值,得到备份数组,然后对备份数组操作,此时其他线程可以并发读取,不影响,对备份数组操作完了之后,此处为添加一个数据,再把真实数组的引用指向备份数组,实现数据的更新,替换掉旧的数组。最后记得释放锁。

出现并发修改异常的原因解读:
类似签到,没有顺序,你争我抢,就可能在纸上划一长道。
在这里插入图片描述
阳哥笔记:
在这里插入图片描述

集合类不安全之set

hashset线程不安全代码展示

在这里插入图片描述
同样的配方,同样的味道。

解决方案

最直接的使用collections工具类,把hashset包装起来。
还有JUC写时复制set。
在这里插入图片描述
打开它的源码,你会发现,两套台子,一套班子,底层是用的写时复制arraylist。
在这里插入图片描述
hashset的底层数据结构就是hashmap,只保留key。
在这里插入图片描述
创建了一个初始大小是16,负载因子0.75的hashmap。
add方法hashset有1个参数,但是hashmap是有两个值的数据结构k-v。
在这里插入图片描述
hashset确实只用到了hashmap的k部分,v部分是一个obj常量。所以add方法只有一个参数即可。
在这里插入图片描述

集合类不安全值map

并发更新异常代码:
在这里插入图片描述

解决方案-并发map

在这里插入图片描述
用法跟hashmap没有区别。
在这里插入图片描述
同样的,用collections工具类也可以。
在这里插入图片描述

transferValue醒脑小练习

题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果:
在这里插入图片描述
需要弄明白这些变量再jvm里面的位置和变量作用域。
栈管运行,堆管存储。第一个age,是存在栈的方法里,值传递,相当于传递了复印件。基本类型传递复印件。
在这里插入图片描述
person的属性改变,改变堆里的的内容,传递的是引用,两个引用指向同一块地址,所以修改的是同一个对象。
在这里插入图片描述
string类型的变量,是因为string分两种,一种是new出来的,一种是直接等于字符串的。
在这里插入图片描述
因为string本身的特殊性,更改的时候,会去池子里找有没有这个xxx,没有就新建,这样方法里面的指针,和string原来的指针就对不上了。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值