2.8.2 并发下的ArrayList,以及源码分析
package 第二章.并发下的ArrayList; import java.util.ArrayList;
import java.util.List; /**
* Created by zzq on 2018/1/19.
*/
public class 并发下的ArrayList {
static ArrayList<Integer> list=new ArrayList<Integer>();
public static class AddThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
list.add(i);
}
} }
public static void main(String[] args) throws InterruptedException {
//ArrayList 网上介绍有容量上限 大约8GB左右
//扩容的公式 ((旧容量 * 3) / 2) + 1 注:这点与C#语言是不同的,C#当中的算法很简单,是翻倍。
/* 一旦容量发生变化,就要带来额外的内存开销,和时间上的开销。
所以,在已经知道容量大小的情况下,推荐使用下面方式进行声明:
List arrayList = new ArrayList(CAPACITY_SIZE);
即指定默认容量大小的方式。
*/
Thread t1=new Thread(new AddThread());
Thread t2=new Thread(new AddThread());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(list.size());
/*上面的程序经过我多次测试得出3个结果
1:size为200000(理想情况)
2:size为小于200000(多次) 因为ArrayList 是一个线程不安全的容器
3:会报异常(这是由于ArrayList在扩容的时候,内部一致性被破坏了,由于没有所的保护,
另一个线程访问到了不一致的背部状态,导致越界问题)
Exception in thread "Thread-3" java.lang.ArrayIndexOutOfBoundsException: 2776
at java.util.ArrayList.add(ArrayList.java:441)
at 第二章.程序的幽灵之隐蔽的错误.并发下的ArrayList$AddThread.run(并发下的ArrayList.java:15)
at java.lang.Thread.run(Thread.java:745)
*/
}
}
1.ArrayListde add()方法:(源码分析)
public boolean add(E e) {
@ 备注1: ensureCapacityInternal(size + 1); //
@ 备注2: elementData[size++] = e;
return true;
}
@ 备注1:解析 其中 ensureCapacityInternal(size + 1)方法是 比较当前list的长度和该list的容量,我们进入该方法继续观看 private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {//判断该list的容量 是否为空,如果为空,给它一个默认的值 10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} 其中 ensureExplicitCapacity(minCapacity) 方法的作用 是判断改list是否需要扩容:我们进入该方法中查看: private void ensureExplicitCapacity(int minCapacity) {
modCount++;//位置加1 // overflow-conscious code
if (minCapacity - elementData.length > 0) //如果当前的size大于此刻list的容量,那么就进行扩容。
grow(minCapacity);
}
其中 grow(minCapacity) 方法为扩容方法(请看源码): private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//容量为原来的1.5倍
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);//将此刻的list拷贝到一个新的扩容之后list中
} @ 备注2:经过以上的判断,然后 elementData[size++] = e; 将该元素加入到该list中 线程安全问题: 通过以上的分析,我们就知道,如果单线程中,是串行的,后面的操作是在之前的操作结束后再次执行,所以list的每一次add方法后都能保持list数据结构的一致 但是在多线程中:没有用到锁机制的前提下线程之间是并行的,那么我们开始分析2种错误形式:(以我们的测试案例来说明) 第一种:size为小于200000(多次) 在 @ 备注1的操作时候2个线程同时拿到一个位置,然后添加,这就会造成 实际是添加2条数据,但是由于 index值是一样的,那么我们实际存入的是一条 第二种:会报异常(数组越界) 发生这种情况,是因为2个线程同时拿到了最后一个位置,但是他们都认为这是最后一个位置,所以list没有进行扩容,所以在其中一个线程执行 @ 备注2 之后,另一个线程也执行了 @ 备注2 这就造成了,本来list的size为10,第二个线程添加的位置是11,所以就会报出 数组越界
2.8.2 并发下的ArrayList,以及源码分析的更多相关文章
- ArrayList迭代器源码分析
集合的遍历 Java集合框架中容器有很多种类,如下图中: 对于有索引的List集合可以通过for循环遍历集合: List<String> list = new ArrayList<& ...
- ArrayList的源码分析
在项目中经常会用到list集合来存储数据,而其中ArrayList是用的最多的的一个集合,这篇博文主要简单介绍ArrayList的源码分析,基于JDK1.7: 这里主要介绍 集合 的属性,构造器,和方 ...
- ArrayList实现源码分析
本文将以以下几个问题来探讨ArrayList的源码实现 1.ArrayList的大小是如何自动增加的 2.什么情况下你会使用ArrayList?什么时候你会选择LinkedList? 3.如何复制某个 ...
- 数据结构——ArrayList的源码分析(你所有的疑问,都会被解答)
一.首先来看一下ArrayList的类图: 1,实现了RandomAccess接口,可以达到随机访问的效果. 2,实现了Serializable接口,可以用来序列化或者反序列化. 3,实现了List接 ...
- 集合之ArrayList的源码分析
转载请注明出处 一.介绍 对于ArrayList,可以说诸位绝不陌生,可以说是在诸多集合中运用的最多一个类之一,那么它是怎样构成,怎样实现的呢,相信很多人都知道数组构成的,没毛病,如果遇到面试的时候, ...
- Java——ArrayList底层源码分析
1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...
- 迎难而上ArrayList,源码分析走一波
先看再点赞,给自己一点思考的时间,思考过后请毫不犹豫微信搜索[沉默王二],关注这个长发飘飘却靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有技术大佬整理 ...
- ArrayList方法源码分析
本文将从ArrayList类的存储结构.初始化.增删数据.扩容处理以及元素迭代等几个方面,分析该类常用方法的源码. 数据存储设计 该类用一个Object类型的数组存储容器的元素.对于容量为空的情况,提 ...
- ArrayList<E>源码分析
ArrayList是按照线性表结构实现的 ArrayList的主要继承结构 public class ArrayList<E> extends AbstractList<E> ...
- ArrayList构造方法源码分析
首先看一下无参的构造方法: private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object ...
随机推荐
- C#网络编程(异步传输字符串) - Part.3
这篇文章我们将前进一大步,使用异步的方式来对服务端编程,以使它成为一个真正意义上的服务器:可以为多个客户端的多次请求服务.但是开始之前,我们需要解决上一节中遗留的一个问题. 消息发送时的问题 这个问题 ...
- Weblogic启动成功,控制台打不开
有时候,我们在linux操作系统上成功启动了weblogic,也查看了7001端口的状态是开启的.但是访问weblogic控制台没有反应,也没有报错. 使用 netstat -ano | grep 7 ...
- bzoj 2865 字符串识别——后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 做出 ht[ ] 之后,sa[ ] 上每个位置和它前面与后面取 LCP ,其中较大的长 ...
- 使用spring框架的JdbcTemplate实现对Oracle数据库的简单操作实例
最近实现了一个小功能,针对Oracle数据库两张关联表进行查询和修改,因为比较简单,所以选择了spring框架里的JdbcTemplate.JdbcTemplate算是老古董了,是当年spring为了 ...
- dubbox下载编译运行demo
最近公司要搞微服务改造,拿了一个小项目开刀,找来找去,还是偏向当当的dubbox作为分布式服务框架.这里介绍下怎么一条龙跑起一个demo. 1.下载代码 因为代码放在github上,所以我们直接用Ec ...
- ubuntu下网卡eth1如何修改为eth0
正常来说,Linux在识别网卡时第一张会是eth0,第二张才是eth1.有时候我们使用虚拟机克隆技术后网卡的信息就会改变,新克隆出来的虚拟主机网卡名字可能变为eth1.无论我们怎么修改都无法改变,这就 ...
- 关于Android Studio上得处女座福音功能——reformat code
在mac上,选中需要的代码,然后 Option+(shift) + Command + L 全部重新排列!!爽飞!
- aop log切面
@Aspect:描述一个切面类,定义切面类的时候需要打上这个注解 @Component:spring-boot配置类 package com.*.*.tools; import org.aspectj ...
- java工具类mht转html格式文件 及简单的HTML解析
package com.szy.project.utils; import java.io.BufferedInputStream; import java.io.BufferedOutputStre ...
- lnmp一键安装包,安装多版本php,并开启redis与swoole
安装多版本的php sudo ./install.sh mphp Install ZendGuardLoader for PHP 7.1... unavailable now. Write ZendG ...