首页 技术 正文
技术 2022年11月21日
0 收藏 701 点赞 2,264 浏览 2566 个字
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,所以就会报出 数组越界
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,950
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,476
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,289
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,107
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,739
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,772