-
Java并发中代替ArrayList保证线程安全的三种方法
2020-09-29 21:03:38一、使用JDK1.0发布的Vector...二、使用集合类的顶层父类Collections类的synchronizedList()方法,传入参数为普通的Arraylist。 List<String> list=new ArrayList<>(); List<String> list2=Collec.一、使用JDK1.0发布的Vector类,因为底层方法使用了synchronized关键字,效率较低,不推荐使用。
List<String> list=new Vector<>();
二、使用集合类的顶层父类Collections类的synchronizedList()方法,传入参数为普通的Arraylist。
List<String> list=new ArrayList<>(); List<String> list2=Collections.synchronizedList(list);
三、JUC下的CopyOnWriteArrayList方法,底层采用写入时复制(推荐使用,性能比Vector高)
List<String> list=new CopyOnWriteArrayList<>();
-
并发下ArrayList为何会出现越界 & 为何用vector代替ArrayList & 使用vector线程一定是安全的嘛?
2019-03-28 19:16:33最近看到书上讲到并发下ArrayList是不安全的可能会导致越界,多线程冲突访问的问题,建议改进的方法是使用vector 代替 ArrayList。脑袋里浮现出几个问题: 1.Arraylist是如何导致越界的问题? 2.vector是如何保证...最近看到书上讲到并发下ArrayList是不安全的可能会导致越界,多线程冲突访问的问题.建议改进的方法是使用vector 代替 ArrayList。于是乎脑袋里浮现出几个问题:
1.Arraylist是如何导致越界的问题?
2.vector是如何保证线程的安全的?
3.使用vector线程就一定安全吗?
4.vector和ArrayList分别适合在什么场景下使用1.ArrayList如何导致越界问题?
1.先看一下错误代码
import java.util.ArrayList; public class ArrayListMultiThread { static ArrayList<Integer> al = new ArrayList<Integer>(10); public static class AddThread implements Runnable { public void run() { for (int i = 0;i <1000000; i++) { al.add(i); } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AddThread()); Thread t2 = new Thread(new AddThread()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(al.size()); } }
运行结果如下这里出现了越界
2.如何导致越界?
1.先看一下需要用到的源码
首先,ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
从上面代码的报错中,我们可以看到在add方法那里出了问题,查看ArrayList中的add源码方法如下:/** * 将指定的元素追加到此列表的末尾。 */ public boolean add(E e) { //添加元素之前,先调用ensureCapacityInternal方法 ensureCapacityInternal(size + 1); //这里看到ArrayList添加元素的实质就相当于为数组赋值 elementData[size++] = e;//将对象e放在数组的末尾 return true; }
可以看出add方法首先调用了ensureCapacityInternal的方法,这个方法是用来得到最小的扩容量。我们再来看看ensureCapacityInternal方法:
DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是在jdk1.8中新加的。作用是根据第一个元素被添加时知道多少个元素去填充把它与EMPTY_ELEMENTDATA区分开来.private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 获取默认的容量和传入参数的较大值 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); //源码中写道 private static final int DEFAULT_CAPACITY = 10; } ensureExplicitCapacity(minCapacity); }
ensureCapacituInternal方法的最后调用了ensureExplicitCapacity方法,这个方法是用来判断是否需要扩容。我们在来看一下这个方法:
//判断是否需要扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; //表现出list结构上被修改的次数 // overflow-conscious code if (minCapacity - elementData.length > 0) //调用grow方法进行扩容,调用此方法代表已经开始扩容了 grow(minCapacity); }
需要的源码差不多都在上面了grow方法就暂时不做描述了。
2.ArrayList越界的逻辑
1.假设列表大小为9,即size=9
2.线程A开始进入add方法,这时它获取到size的值为9,调用ensureCapacityInternal方法进行容量判断。
3.线程B此时也进入add方法,它获取到size的值也为9,也开始调用ensureCapacityInternal方法。
4.线程A发现需求大小为10,而elementData的大小就为10,可以容纳。于是它不再扩容,返回。
5.线程B也发现需求大小为10,也可以容纳,返回。
6.线程A开始进行设置值操作, elementData[size++] = e 操作。此时size变为10。
7.线程B也开始进行设置值操作,它尝试设置elementData[10] = e,而elementData没有进行过扩 容,它的下标最大为9。于是此时会报出一个数组越界的异常ArrayIndexOutOfBoundsException3.ArrayList导致多线程冲突访问。
执行上面的代码我们会发现有的时候不会报错,但是结果会远小于正确值。这是由于多线程访问冲突,使的保存容器大小的变量被多线程不正常的访问,同时两个线程也同时对ArrayList中的同一个位置进行复制导致的。
2. vector是如何保证线程安全的呢?
上述的错误代码如果将ArrayList都换成vector,执行的结果就是正确的了。那么vector是如何保证线程的安全的呢?看源码发现vector中一些关键的方法都用synchronized修饰,这就使得每次只能有一个线程去访问,从而保证安全。
3. 使用vector一定能保证线程的安全吗?
很多人都会问这个问题,答案是不安全的,虽然很多方法都用synchronized修饰,保证所有对外的接口都以vector为锁,但是在单个方法的原子性方面,并不能保证符合操作的原子性。对于复合操作vector和ArrayList一样都需要进行同步处理。所以,如果是这样的话,那么用vector和ArrayList就没有区别了。因为 synchronized 的开销是巨大的,vector还会导致一些性能下降的问题。
书上说建议使用vector代替ArrayList,看完别人的讲解发现vector还是不能乱用的,现在挺迷糊的。
4.vector和ArrayList分别适合在什么场景下使用
这个问题暂时未找到答案。o(╥﹏╥)o
-
ArrayList 和 Vector 的区别?为什么要用Arraylist代替Vector?
2020-04-02 09:40:15Vector 类中所有的方法都是同步的,可以由两个线程安全的访问同一个Vector对象,但是一个线程访问Vector 的话就会在同步操作上耗费大量的时间。 ArrayList 不是同步的,所有在不需要保证线程安全时建议使用ArrayList...Vector 类中所有的方法都是同步的,可以由两个线程安全的访问同一个Vector对象,但是一个线程访问Vector 的话就会在同步操作上耗费大量的时间。
ArrayList 不是同步的,所有在不需要保证线程安全时建议使用ArrayList 。
-
ArrayList线程安全处理
2021-02-01 11:23:43//1.Collections.synchronizedList ... 使用线程安全的 CopyOnWriteArrayList 代替线程不安全的 ArrayList。 List<Object> list2=new CopyOnWriteArrayList<>(); //3.使用ThreadLocal 推荐 Threa//1.Collections.synchronizedList List<Object> list1= Collections.synchronizedList(new ArrayList<>()); //2. 使用线程安全的 CopyOnWriteArrayList 代替线程不安全的 ArrayList。 List<Object> list2=new CopyOnWriteArrayList<>(); //3.使用ThreadLocal 推荐 ThreadLocal<List<Object>> threadList=new ThreadLocal<List<Object>>(){ @Override protected List<Object> initialValue(){ return new ArrayList<>(); } };
-
ArrayList、HashMap、HashSet是线程不安全的,高并发下如何解决?
2020-01-02 21:00:341.故障现象 :ArrayList的add()方法并没有使用synchronized所以是线程不安全的,会造成java.util.ConcurrentmodificationException(并发修改异常) 2.导致原因:并发争抢修改导致 3.解决办法(以ArrayList为例,其他... -
ArrayList、Vector、HashMap、Hashtable中那些是线程安全的。HashMap、Hashtable那个可以有空的key及value
2009-12-10 23:39:00HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable。 这里简单分析他们的区别。 1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要... -
ArrayList 与 Vector 区别
2020-07-20 20:43:39ArrayList不是同步的,线程不安全,但速度较快,Vector是同步的,速度慢,但已经被ArrayList代替。 -
concurrentarraylist_为什么java.util.concurrent 包里没有并发的ArrayList实现?
2020-12-21 02:17:28原文链接作者:Stephen C 校对:方腾飞问:JDK 5在java.util.concurrent里引入了ConcurrentHashMap,在需要支持高并发的场景,我们可以使用它代替HashMap。...难道在多线程场景下我们只有Vector这一种线程安全的... -
为什么java.util.concurrent 包里没有并发的ArrayList实现?
2018-02-19 22:32:12但是为什么没有ArrayList的并发实现呢?难道在多线程场景下我们只有Vector这一种线程安全的数组实现可以选择么?为什么在java.util.concurrent 没有一个类可以代替Vector呢?答:我认为在java.util.con... -
为什么java.util.concurrent 包里没有并发的ArrayList实现
2017-05-02 15:59:00原文链接作者:Stephen C译者:郑旭东校对:方腾飞 问:JDK 5在java.util.concurrent里...但是为什么没有ArrayList的并发实现呢?难道在多线程场景下我们只有Vector这一种线程安全的数组实现可以选择么?为什么在ja... -
Vector和ArrayList异同
2018-05-23 14:15:51值得注意的是Vector与ArrayList唯一的区别是,Vector是线程安全的,即它的大部分方法都包含有关键字synchronized,因此,若对于单一线程的应用来说,最好使用ArrayList代替Vector,因为这样效率会快很多(类似的情况... -
Vector和ArrayList异同 ?
2018-05-23 19:39:44值得注意的是Vector与ArrayList唯一的区别是,Vector是线程安全的,即它的大部分方法都包含有关键字synchronized,因此,若对于单一线程的应用来说,最好使用ArrayList代替Vector,因为这样效率会快很多(类似的情况... -
1. ArrayList和LinkedList总结
2017-07-31 19:42:31ArrayList类图总结 ArrayList的默认容量是10/** * Default initial capacity. ...不同于Vector,ArrayList是线程不安全的,可以使用并发容器CopyOnWirteArrayList代替 ArrayList底层是使用对象数组实现的,继承了Ab -
java的各种集合为什么不安全(List、Set、Map)以及代替方案
2020-10-13 22:09:08我们已经知道多线程下会有各种不安全的问题,都知道并发的基本解决方案,这里对出现错误的情况进行一个实际模拟,以此能够联想到具体的生产环境中。 一、List 的不安全 1.1 问题 看一段代码: public static void ... -
concurrentarraylist_为什么java.util.concurrent 包里没有并发的ArrayList实现-阿里云开发者社区...
2020-12-21 02:18:05原文链接作者:Stephen C译者:郑旭东校对:方腾飞问:JDK ...但是为什么没有ArrayList的并发实现呢?难道在多线程场景下我们只有Vector这一种线程安全的数组实现可以选择么?为什么在java.util.concurrent 没有一个... -
concurrentarraylist_为什么java.util.concurrent 包里没有并发的ArrayList实现?-阿里云开发者社区...
2020-12-30 13:10:12原文链接作者:Stephen C译者:郑旭东校对:方腾飞问:JDK ...但是为什么没有ArrayList的并发实现呢?难道在多线程场景下我们只有Vector这一种线程安全的数组实现可以选择么?为什么在java.util.concurrent 没有一个... -
集合的线程安全问题
2020-09-05 18:57:571.如何解决ArrayList线程不安全问题呢? 1.用Vector代替ArrayList 2.用Collections.synchronized(new ArrayList<>()) List<Object> arrayList = Collections.synchronizedList(new ArrayList<>... -
list的线程安全的类型
2016-09-17 23:58:22list安全可以用Vector代替,或者用Collections.synchronizedList(new ArrayList())来定义一个线程安全的list。 -
线程安全-同步容器(同步容器不一定就是线程安全的)
2018-04-26 17:11:05ArrayList是线程不安全的,用Vector、Stack代替, 但是,Vector不一定就是安全的,若使用forEach或者Iterator遍历集合的时候做更新操作,会引发异常,而使用for循环则不会; package com.concurrent.example; ... -
JDK源码分析——Vector(线程安全的队列)
2019-01-21 16:24:53如果不需要线程安全的实现,建议使用ArrayList代替Vector * 几乎所有的方法都是synchronized方法修饰的。 */ package java.util; import java.io.IOException; import java.io.ObjectInput... -
Java 中的数组是线程安全的么?
2008-11-15 16:31:11在《Practical Java》一书中Peter Haggar建议使用一个简单的数组(Array)来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为[b]使用数组(Array)避免了同步[/b]、额外的方法调用和不必要的重新... -
通过并发容器来代替同步容器,可以极大地提高伸缩性并降低风险。
2020-11-27 17:06:01同步容器类包括Vector和Hashtable,二者是早期JDK的一部分,这两个容器的实现和早期的ArrayList和HashMap代码实现基本一样,此外还包括在JDK1.2中添加的一些功能相似的类,这些同步的封装器类是由Collections.... -
Vector 向量 LinkedList ArrayLis的构造器 Map 容器接口 Map的遍历方式 HashMap
2020-01-14 21:24:09与ArrayList像,都是由数组实现内部存储结构, 已经被ArrayList代替 Vector线程安全,效率较低,ArrayList线程不安全,效率较高,重效率轻安全 扩容:每次扩容原容量的2倍,没有ArrayList节省空间 LinkedList 就是在存储数据...