面试题答案
一键面试Vector
- 线程安全实现方式:
Vector
的大部分方法(如add
、get
、remove
等)都使用synchronized
关键字进行同步。这意味着在同一时间,只有一个线程可以访问这些方法,从而保证了线程安全。例如:
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
- 线程安全实现方式:
Hashtable
- 线程安全实现方式:类似
Vector
,Hashtable
的大多数方法(如put
、get
、remove
等)也通过synchronized
关键字实现同步。这使得在多线程环境下,对Hashtable
的操作是线程安全的。例如:
public synchronized V put(K key, V value) { // 检查键是否为null if (value == null) { throw new NullPointerException(); } // 计算哈希值 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry!= null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; }
- 线程安全实现方式:类似
ConcurrentHashMap
- 线程安全实现方式:
- 分段锁机制(早期版本):在Java 7及以前版本,
ConcurrentHashMap
采用分段锁(Segment
)机制。它将数据分成多个段(Segment
),每个段就像一个小的Hashtable
,都有自己的锁。不同段之间的操作可以并发执行,只有访问同一Segment
时才会竞争锁,大大提高了并发性能。 - CAS和 synchronized 结合(Java 8及以后):Java 8中,
ConcurrentHashMap
摒弃了分段锁机制,采用数组 + 链表/红黑树的数据结构。在更新操作时,使用CAS
(Compare - and - Swap)操作来保证对数组元素的原子性更新,对于链表或红黑树节点的操作使用synchronized
关键字。例如,在插入元素时,首先使用CAS
尝试将元素插入数组,如果失败(说明有其他线程同时在操作),则对该位置的链表或红黑树加synchronized
锁进行操作。
- 分段锁机制(早期版本):在Java 7及以前版本,
- 线程安全实现方式:
CopyOnWriteArrayList
- 线程安全实现方式:
CopyOnWriteArrayList
采用写时复制的策略。当对列表进行修改(如add
、remove
等操作)时,会先复制一份原数组,在新数组上进行修改操作,然后将原数组引用指向新数组。而读操作(如get
等)则直接读取原数组,不涉及锁操作。由于读操作和写操作使用不同的数组,所以读操作是线程安全的,而写操作虽然需要复制数组,但也通过加锁(ReentrantLock
)保证了线程安全。例如:
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
- 线程安全实现方式:
CopyOnWriteArraySet
- 线程安全实现方式:
CopyOnWriteArraySet
内部是基于CopyOnWriteArrayList
实现的。它的线程安全机制和CopyOnWriteArrayList
相同,即写时复制。在添加元素时,会调用CopyOnWriteArrayList
的addIfAbsent
方法,同样是先复制数组,在新数组上添加元素,然后更新数组引用,保证了线程安全。读操作则直接读取原数组,不涉及锁操作,从而实现线程安全。
- 线程安全实现方式: