java中List的并发操作

前言

java提供了好多数据结构,很方便。从用到这些东西的那天起就在考虑过并发,并发是一个老生常谈的问题。
由于不是java入行的,先前问过人家LinkedList之类的是不是线程安全的,人斩钉截铁答曰:是的。真不知道人家那十几K的工资是怎么拿的。。。
此文是篇List并发操作的笔记,不贴代码而是罗列过程和总结。

List

List常用的是ArrayList和LinkedList。
我参考的源码出自androdStudio自带,突然发现AS自带了一部分java的源码,好棒。而且,AS还有强大的反编译class文件功能,简直逆天。
List常用的操作:add和remove。

ArrayList

概括:经观源码,本质上就是个数组。具备自动扩容能力,自动扩容算法简单粗暴。使用时,最好在创建时就预估需求并设定capcity,以避免容量变动带来的开销。
操作:每次add&remove都是一次搬家–自动脑补一个数组中数据的插入和拔除。

LinkedList

概括:经观源码,本质上就是个双向链表。链表不需要capcity的设定,有容乃大。
操作:每次add&remove都是几对小指针(pre&next)的挥舞–你练习过数据结构,便不需我多言。

小区别

ArrayList和LinkedList是一对双生。
前者爱搬家,放不下了还要扩地盘。但是东西一找一个准,数组们的种族天赋–下标就是个hash的key。
后者放东西取东西也都方便,反正它自个儿也不知道放在哪。但是你要想找第几个的时候,它就得从第一个开始数起了。
所以,它们各自发挥种族属性。如果不需要指定location的add&remove,那LinkedList绝对是首选。capacity越大其add&remove的性能相比ArrayList就越突出。再所以,ArrayList除了拿来保存类似于:设备类对象–这种客观存在几乎不会去变更,只需要被get的东西 之外,其余场景还是少用。

并发

总算切入并发的正题了。
写了个小实验:两个线程,一个add,一个remove,保持线程共振。
由于add&remove操作时间太短,一定要共振才能有效果。实验中,哪怕是在remove前多了一行print打印都会把两个操作给岔开,就不会有并发竞争的效果了。
实验现象:remove操作抛出NoSuchElementException。当然remove之前我是检测过isEmpty(笑话,这个怎么会忘)。观源码,其关口:通过判断voidLink.next是否指向自身,指向自身就是链表为空嘛,好理解。
分析:先前已经检测了isEmpty,那链表必然不为空,正常的话voidLink.next就不该指向自己。此处先想到的是:add操作引起问题。因为,isEmpty检测的是size==0,而add会size++。如果,add时先size++再添加数据,出现这种很正常。但事实是,add时先添加数据再size++。(废话,正常人都会这样做)
其实,出现这个问题的大致原因想想就知道了。双向链表的pre&next两根小指针,那么脆弱。add&remove的时候都得被掰来掰去,一旦操作不是原子性的出问题很正常,而且完全无法预料pre&next会指到哪。
上面的只是思路,而实际问题场景是:voidLink.next原本指向了链表中唯一的element,在此element被remove,add还未完成,该element.next还是指向的voidLink而不是指向新add的element,所以就出问题。这段话其实没必要,完全只是描述了一种问题场景罢了。
然后,联想下ArrayList,乱并发肯定会导致搬家总动员。
总之,对待List别乱来。
你要问为什么你乱来了没碰到问题。那是因为我们的操作往往是低频的,好比两个奸夫,一个白天一个晚上岔开了。但万一一共振撞上了,就出事了。脑补下这种错误肯定是很诡异很难被debug的。

措施

最后,怎么解决问题呢。
我觉得有两招:synchronized block&Collections.synchronizedList。
用synchronized block框起来总觉得碍眼影响代码阅读。
还是刷个buff的好,Collections.synchronizedList可以返回一个List,就是不能被cast成LinkedList,因为它根本就是另外一个类了–一个添加了mutex的以List作为成员的类。另外,虽然只能调用add&remove,但对于LinkedList,add默认就是addLast,remove(0)默认就是removeFirst。
此致!
貌似,有一个东西叫ConcurrentLinkedQueue。。。后面看下它的实现!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值