Vector和ArrayList区别以及Vector并非是绝对线程安全的

转自:https://www.cnblogs.com/zhangzongle/p/5432212.html

Java中Vector和ArrayList的区别

首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList、Vector和LinkedList。List用于存放多个元素,能够维护元素的次序,并且允许元素的重复。3个具体实现类的相关区别如下:

  1. ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
  2. Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
  3. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
  4. vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。
  5. 如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度
    的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。

  6. 如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而
    如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用Linkedlist,因为它移动一个指定位置的数据
    所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。
    ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,
    都允许直接序号索引元素,但是插入数据要设计到数组元素移动 等内存操作,所以索引数据快插入数据慢,
    Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差
    ,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

  7. 笼统来说:LinkedList:增删改快
                  ArrayList:查询快(有索引的存在)

关于Vector,真是有点坑啊,阿里我尝试去面试,那位面试官问我,Vector你说是线程安全的,那是怎么实现安全的

我回答:他的方法里很多都用了synchronized关键字啊,实现了同步

他又问我,那Vector还有其他手段实现了同步么?我当时想,源码里没别的复杂的东西了,就是靠这个关键字搞得

难不成是我没看到,眼瞎了?有知道的告诉我下啊,(那个modcount不是,就不用跟我说了)

Vector还真不算是线程安全,https://blog.csdn.net/zlp1992/article/details/50433778这里就很详细的展示了什么叫

实力坑爹:

先看段代码:

    private static Vector<Integer> vector=new Vector();

    public static void main(String[] args) {
        while(true){
            for(int i=0;i<10;i++){
                vector.add(i); //往vector中添加元素
            }
            Thread removeThread=new Thread(new Runnable() {         
                @Override
                public void run() {
                    //获取vector的大小
                    for(int i=0;i<vector.size();i++){
                        //当前线程让出CPU,使例子中的错误更快出现
                        Thread.yield();
                        //移除第i个数据
                        vector.remove(i);
                    }
                }
            });
            Thread printThread=new Thread(new Runnable() {          
                @Override
                public void run() {
                    //获取vector的大小
                    for(int i=0;i<vector.size();i++){
                        //当前线程让出CPU,使例子中的错误更快出现
                        Thread.yield();
                        //获取第i个数据并打印
                        System.out.println(vector.get(i));
                    }
                }
            });         
            removeThread.start();
            printThread.start();
            //避免同时产生过多线程
            while(Thread.activeCount()>20);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

运行之后,会有如下异常:

4
6
6
1
8
3
5
Exception in thread "Thread-285" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 11
    at java.util.Vector.get(Unknown Source)
    at VectorTest$2.run(VectorTest.java:31)
    at java.lang.Thread.run(Unknown Source)
7
9
0
6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这表明上述代码在使用Vector的时候线程并不是安全的,使用get访问Vector时出现了越界。这是为什么呢? 
Vector类中对get以及remove,size方法都加了synchronized关键字来保证同步,也就说当一个线程调用了这些方法时,其他线程不能再同时调用这些方法。换言之,不能出现两个及两个以上的线程在同时调用这些同步方法。 
那么为什么例子中会出现问题呢?这是因为 例子中有些线程连续调用了两个或两个以上的同步方法。 
例子中 removeThread线程先调用了vector.size()方法获得vector的大小,接着调用vector.remove(i)移除第i个元素;而printThread线程也先调用vector.size()方法获得vector的大小,接着调用vector.get()获得第i个元素。

假设此时vector大小为5,此时printThread线程执行到 i=4 ,进入for循环但在 System.out.println(vector.get(i));之前 printThread线程的CPU时间片已到,线程printThread转入就绪状态; 
此时removeThread线程获得CPU开始执行,把vector的5个元素全删除了,这是removeThreadCPU时间片已到; 
接着printThread获得CPU进行执行,由于之前printThread中的i==4,于是调用vector.get(4)获取元素,此时由于vector中的元素已被removeThread线程全部删除,因此报错。

总的来说,vector保证了其同步方法不能被两个及两个以上线程同时访问,但是我们自己的操作会使得即使使用了Vector线程也不安全,如果不大清楚,最好自己加上 synchronized进行同步吧。

以上是copy人家的实验,充分展示了Vector不靠谱的一点,所以即便是应用java封装好的所谓的线程安全的类,也要自己好好

思考一下,小心被坑。。。。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值