云计算百科
云计算领域专业知识百科平台

【Vector】【ConCurrentHashMap】线程安全

这两个集合,是 Java 中线程安全集合的典型代表,也是面试【高频原题】:Vector是怎么保证线程安全的?、ConcurrentHashMap线程安全的实现原理?、HashMap和ConcurrentHashMap的区别?

1.Vector 是 ArrayList 的线程安全版,ConcurrentHashMap 是 HashMap 的线程安全版。Vector 是通过「在所有对外的公有方法上,直接加 synchronized 同步锁」实现的线程安全。Vector 的底层和 ArrayList 完全一样,都是基于数组实现,区别只在方法的修饰符上:ArrayList 的所有方法都是普通方法,无任何锁;Vector 的所有核心方法(增删改查、扩容、遍历),都被 synchronized 关键字修饰。

// Vector的添加元素方法:加了synchronized
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}

// Vector的删除元素方法:加了synchronized
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount – index – 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[–elementCount] = null;
return oldValue;
}

// Vector的获取元素方法:加了synchronized
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}

锁的本质:Vector 的锁是「对象级别的独占锁」

synchronized 加在普通方法上,等价于给 Vector对象本身 加锁 → 一把锁锁住整个 Vector 对象。

  • 当任意一个线程调用 Vector 的任意一个方法(add/remove/get)时,都会独占这把锁;
  • 此时其他线程,无论想调用 Vector 的任何方法,都会被阻塞等待,直到当前线程释放锁;
  • 比如:线程 A 调用add(),线程 B 调用get(),B 也会被阻塞,必须等 A 执行完。

2. Vector 线程安全的优缺点(面试必考,答全加分)

优点:实现简单、绝对线程安全

synchronized 是 JDK 原生的同步锁,保证了所有操作的原子性,只要用 Vector,在多线程下无论怎么操作,都不会出现数据错乱、并发修改异常,安全性无任何问题。

缺点:效率极低,性能差(致命缺点) → 开发中几乎不用 Vector

这是 Vector 的核心问题,也是为什么现在项目中很少用 Vector的原因,根源就是它的锁机制:锁粒度太大!

  • 锁粒度:指「被锁住的资源范围」,Vector 是粗粒度锁(锁整个对象);
  • 问题 1:读写互斥 → 哪怕是「只读操作」(get 查询),也会被加锁,多个线程并发查询时,只能串行执行,查询效率暴跌;
  • 问题 2:操作互斥 → 增删改查所有操作都抢同一把锁,哪怕两个线程操作 Vector 的不同位置的元素,也会互相阻塞;

通俗比喻:Vector 就像一个只有一个收银台的超市,不管你是买东西、退货、结账,都要排队等这一个收银台,效率极低。

3.ConcurrentHashMap 是 Java 中并发集合的王者,是 HashMap 的线程安全版,也是开发中多线程下操作键值对的首选。核心优势:ConcurrentHashMap 解决了 Vector 的痛点 → 线程安全的同时,效率极高!

核心设计:分段锁(Segment)机制 → 把 HashMap「分块加锁」

JDK7 的 ConcurrentHashMap,在 HashMap 的基础上,做了一层封装:

  • 内部维护了一个 Segment[] 分段数组,一个 Segment 就是一个「小 HashMap」;
  • 每个 Segment 都继承了 ReentrantLock(可重入锁),每个 Segment 都有自己独立的一把锁;
  • 当线程要操作 ConcurrentHashMap 时,只会锁住「当前元素所在的 Segment」,不会锁住整个集合。
  • 比喻:ConcurrentHashMap(JDK7)就像一个有多个收银台的超市,每个收银台对应一个区域的商品,你买哪个区域的商品,就只在这个收银台排队,不会影响其他收银台的人。
  • HashMap、Hashtable、ConcurrentHashMap 的区别?

    • HashMap:线程不安全,效率高,底层数组 + 链表 + 红黑树,允许 key/value 为 null;
    • Hashtable:线程安全,效率极低(全表锁),底层数组 + 链表,不允许 key/value 为 null;
    • ConcurrentHashMap:线程安全,效率极高(细粒度锁),底层数组 + 链表 + 红黑树,不允许 key/value 为 null,是开发中多线程下的首选。

    为什么开发中不用 Vector 和 Hashtable,而用 ConcurrentHashMap?

    因为 Vector 和 Hashtable 是粗粒度锁,锁粒度太大,效率极低,在高并发场景下性能暴跌;而 ConcurrentHashMap 是细粒度锁,兼顾线程安全和效率,是专门为高并发设计的集合,性能远超 Vector 和 Hashtable。

    ConcurrentHashMap 为什么不允许 key/value 为 null?

    为了避免歧义!因为 ConcurrentHashMap 的 get 方法无锁,如果允许 null,当 get 返回 null 时,无法判断是「key 不存在返回 null」还是「key 存在但 value 就是 null」,而 HashMap 是单线程的,可以通过 containsKey 判断,ConcurrentHashMap 是多线程的,containsKey 和 get 之间可能有线程修改数据,判断结果不可靠,因此直接禁止 null 值。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【Vector】【ConCurrentHashMap】线程安全
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!