关于并发编程与线程安全的思考与实践
作者 | 京东云开发者-京东健康 张娜
原文链接:https://my.oschina.net/u/4090830/blog/8724887
一、并发编程的意义与挑战
二、Java 并发编程
2.1 Java 内存模型
2.2 Java 中的并发关键字
2.3 Java 中的并发容器与工具类
2.3.1 CopyOnWriteArrayList
publicEget(int index){
returnget(getArray(), index);
}
publicbooleanadd(E e){
finalReentrantLock lock =this.lock;
lock.lock();
try{
Object[] elements =getArray();
int len = elements.length;
Object[] newElements =Arrays.copyOf(elements, len +1);
newElements[len]= e;
setArray(newElements);
returntrue;
}finally{
lock.unlock();
}
}
2.3.2 Collections.synchronizedList(new ArrayList<>());
publicvoidadd(int index,E element){
// SynchronizedList 就是在 List的操作外包加了一层synchronize同步控制
synchronized(mutex){list.add(index, element);}
}
publicEremove(int index){
synchronized(mutex){return list.remove(index);}
}
2.3.3 ConcurrentLinkedQueue
publicbooleanoffer(E e){
checkNotNull(e);
finalNode<E> newNode =newNode<E>(e);
for(Node<E> t = tail, p = t;;){
Node<E> q = p.next;
if(q ==null){
// p是尾节点,CAS 将p的next指向newNode.
if(p.casNext(null, newNode)){
if(p != t)
//tail指向真正尾节点
casTail(t, newNode);
returntrue;
}
}
elseif(p == q)
// 说明p节点和p的next节点都等于空,表示这个队列刚初始化,正准备添加节点,所以返回head节点
p =(t !=(t = tail))? t : head;
else
// 向后查找尾节点
p =(p != t && t !=(t = tail))? t : q;
}
}
三、线上案例
3.1 问题发现
3.2 排查问题的详细过程
// 多个线程结果集合
List<DoctorDiagImButtonInfoDTO> multiButtonList =newArrayList<>();
// 多线程并行处理
Future<List<DoctorDiagImButtonInfoDTO>> multiButtonFuture = joyThreadPoolTaskExecutor.submit(()->{
List<DoctorDiagImButtonInfoDTO> multiButtonListTemp =newArrayList<>();
buttonTypes.forEach(buttonType ->{
multiButtonListTemp.add(appButtonInfoMap.get(buttonType));
});
multiButtonList.addAll(multiButtonListTemp);
return multiButtonListTemp;
});
publicbooleanaddAll(Collection<? extends E> c){
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew);// Increments modCount
//以当前size为起点,向数组中追加本次新增对象
System.arraycopy(a,0, elementData, size, numNew);
//更新全局变量size的值,和上一步是非原子操作,引发并发问题的根源
size += numNew;
return numNew !=0;
}
privatevoidensureCapacityInternal(int minCapacity){
if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
minCapacity =Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
privatevoidensureExplicitCapacity(int minCapacity){
modCount++;
// overflow-conscious code
if(minCapacity - elementData.length >0)
grow(minCapacity);
}
privatevoidgrow(int minCapacity){
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity +(oldCapacity >>1);
if(newCapacity - minCapacity <0)
newCapacity = minCapacity;
if(newCapacity - MAX_ARRAY_SIZE >0)
newCapacity =hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData =Arrays.copyOf(elementData, newCapacity);
}
publicbooleanaddAll(Collection<? extends E> c){
Object[] a = c.toArray();
int numNew = a.length;
//第1次停顿,获取当前size
try{
Thread.sleep(1000*timeout1);
}catch(InterruptedException e){
e.printStackTrace();
}
ensureCapacityInternal(size + numNew);// Increments modCount
//第2次停顿,等待copy
try{
Thread.sleep(1000*timeout2);
}catch(InterruptedException e){
e.printStackTrace();
}
System.arraycopy(a,0, elementData, size, numNew);
//第3次停顿,等待size+=
try{
Thread.sleep(1000*timeout3);
}catch(InterruptedException e){
e.printStackTrace();
}
size += numNew;
return numNew !=0;
}
3.3 解决问题
List<DoctorDiagImButtonInfoDTO> multiButtonList =Collections.synchronizedList(newArrayList<>());
3.4 总结反思
END
🌟 活动推荐
2023 年 5 月 27-28 日,GOTC 2023 全球开源技术峰会将在上海张江科学会堂隆重举行。
为期 2 天的开源行业盛会,将以行业展览、主题发言、特别论坛、分论坛、快闪演讲的形式来诠释此次大会主题 ——“Open Source, Into the Future”。与会者将一起探讨元宇宙、3D 与游戏、eBPF、Web3.0、区块链等热门技术主题,以及 OSPO、汽车软件、AIGC、开源教育培训、云原生、信创等热门话题,探讨开源未来,助力开源发展。
长按识别下方二维码立即查看 GOTC 2023 详情/报名。
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章