Vector真的是线程安全的吗

/ Code / 1 条评论 / 280浏览
转载请标明出处^_^
原文首发于: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 仍然需要进行同步处理。

亲,博主的微信公众号

‘程序员小圈圈’开始持续更新了哟~~

长按图片识别二维码或者微信扫描二维码或者直接搜索名字 ‘CXYXQQ’ 即可关注本公众号哟~~

不只是有技术哟~~

还可以学下教育知识以及消遣娱乐哟~~

求关注哟~~

  1. 水军来了,代刷评论。1元100条。量大从优。

    回复