欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vector真的是线程安全的吗

程序员文章站 2022-03-22 22:16:34
...
转载请标明出处^_^
原文首发于:www.zhangruibin.com
本文出自于:RebornChang的博客

Vector真的是线程安全的吗

Vector类 继承了 AbstractList<E> 实现了 List<E>, RandomAccess, Cloneable, java.io.Serializable接口。
 AbstractList 类 继承了 AbstractCollection实现了 List<E>;
 AbstractCollection类 继承了 Collection<E>;
 Collection接口 继承了 Iterable接口;

查看源码得知,所谓安全,是在方法上加上了synchronized关键字以保证单线程持有。
但是,使用synchronized关键字做线程安全的话,效率低,且不可修改。因为synchronized关键字是JVM级别的,不可控,靠JVM内部机制进行关键字识别以及对象的持有和释放,因此,使用Vector的话,效率很慢。
而且,使用了synchronized关键字,是可以达到局域性线程同步,但是并不是真正的线程安全。因为:单个方法的原子性(注:原子性,程序的原子性即不会被线程调度机制打断),并不能保证复合操作也具有原子性。
即:复合操作有可能打破单方法的原子性。

举个栗子:

if (!vector.contains(element)) 
   vector.add(element); 
   then do sm
}

上面是经典的 put-if-absent 情况,尽管 contains, add 方法在vector源码中都使用synchronized进行同步了.

vector中的源码


public boolean contains(Object o) {
        return indexOf(o, 0) >= 0;
    }
      public synchronized int indexOf(Object o, int index) {
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

但作为 vector 之外的使用环境,仍然存在 race condition: 因为虽然条件判断 if (!vector.contains(element))与方法调用 vector.add(element); 都是原子性的操作 (atomic),但在 if 条件判断为真后,那个用来访问vector.contains 方法的锁已经释放,在即将的 vector.add 方法调用 之间有间隙,在多线程环境中,完全有可能被其他线程获得 vector的 lock 并改变其状态, 此时当前线程的vector.add(element); 正在等待。只有当其他线程释放了 vector 的 lock 后,vector.add(element); 继续,但此时它已经基于一个错误的假设了。

因此:
单个的方法 synchronized 了并不代表组合(compound)的方法调用具有原子性,使 compound actions 成为线程安全的可能解决办法之一还是离不开intrinsic lock (这个锁应该是 vector 的,但由 client 维护):
所以我们在使用的时候还要这样,在putIfAbsent的时候,先将vector对象进行加锁:

 public static void main(String[] args) {
        Vector vector = new Vector();
        vector.add("aaa");
        vector.add("666");
        putIfAbsent(vector,"666");
    }

    public static void putIfAbsent(Vector vector,Object object) {
        synchronized(vector) {
            if (!vector.contains(object)) {
                vector.add(object);
            }else {
                System.out.println("The vertor is contains the object of "+object.toString());
            }
        }
    }
    
    结果输出:
    The vertor is contains the object of 666
    

结论:
Vector 和 ArrayList 实现了同一接口 List, 但所有的 Vector 的方法都具有 synchronized 关键修饰。但对于复合操作,Vector 仍然需要进行同步处理。

相关标签: Vector 容器