Java中Vector的操作一定是线程安全的嘛?
Java中Vector类是JDK1.2加入的遗留集合,其内部的方法主要是通过synchronized关键字进行封装,保证这个类是一个线程安全的类,那么是不是vector的操作一定是线程安全的呢?本文将带你分析不一样的vector。
01
vector简介
首先,我们使用简单的描述vector的重要方法。这里是vector的主要方法之一:
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
从vector的两个主要方法,get方法和set方法来看,vector实现线程安全的方法主要使用Java中的关键字synchronized,关于synchronized关键字,不明白其底层实现的原理可以看我的上一篇文章Java并发之synchronized关键字。从synchronized关键字的原理来看,这两个方法是线程安全的,方法通过持有该实例的监视器仅仅只是允许一个线程对于vector进行操作,如果对于监视器底层原理实现不清楚的同学,可以看一下以前的文章Java并发之Monitor实现。那么什么时候不安全呢?下面一节将会详细讲解。
02
vector非线程安全操作
这里我们首先看一下下面的代码:
public static Object getLast(Vector v)
{
int lastIndex=v.getList()-1;
return v.get(lastIndex);
}
public static void deleteLast(Vector v)
{
int lastIndex=v.getList()-1;
v.remove(lastIndex);
}
这些代码看似无害,无论多少线程同时调用他们,这些方法都是不会使vector变坏。但是调用者有不同的观点,如果在vector含有10个元素时,线程B调用方法getLast,同样地,线程A调用deleteLast方法。当两个线程交替的执行时,那么将会抛出ArrayIndexOutOfBoundsException 。
如果线程B调用get方法是在线程A中的remove方法调用之后,下标9就不再是一个合法的下标。显然,对于两个同步的方法,在多线程下这是不安全的。那么如何保证先这样的操作是线程安全的呢?
03
保证线程安全
vector的两个原子操作复合成为一个新的方法,显然这个方法是非线程安全的,我们需要使用锁来保证这两个原子操作组合而成的方法的原子性。换句话说,保证这个符合操作的线程安全,我们需要添加额外的面向客户端的锁来监视这个方法的行为。
public static Object getLast(Vector v)
{
synchronized(v)
{
int lastIndex=v.getList()-1;
return list.get(lastIndex);
}
}
public static void deleteLast(Vector list)
{
synchronized(v)
{
int lastIndex=v.getList()-1;
list.remove(lastIndex);
}
}
上面的代码使用synchronized关键字来保证两个原子操作的复合操作来进行保证原子性。
04
总结
vector的单个操作时原子性的,也就是线程安全的。但是如果两个原子操作复合而来,这个组合的方法是非线程安全的,需要使用锁来保证线程安全。
▼
往期精彩回顾
▼
点击上方二维码,关注我们
15
好看你就点点我