1.Hashtable和Hashmap的区别
2.ConcurrentHashMap
3.CopyOnWriteArrayList
4.CopyOnWriteArraySet
5.CopyOnWrite机制
6.Vector
7.StringBuffer和StringBuilder的区别
Hashtable 和Hashmap
两者均是存储(Key-Value)键值对映射,主要区别在于Hastable是线程安全的,Hashmap是线程不安全的,Hashtable的主要方法都使用了synchronized关键字进行隐式加锁,保证了线程安全。部分源码截图
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
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;
}
Hashmap和hashtable 都有实现接口如下接口
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
ConcurrentHashMap也是线程安全,相比于Hashtable区别在于syncchronized使用位置不一样,Hashtable是对方法加锁,ConcurrentHashMap是对代码块加锁,因此,ConcurrentHashMap效率更高。
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}
CopyOnWriteArrayList使用了ReentrantLock进行加锁,对于读操作没有加锁,而对写操作进行了加锁,适合于读操作远远大于写操作的场合,源码如下:
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
....
}
CopyOnWriteArraySet是在CopyOnWriteArrayList上使用了装饰者模式,很多方法都是使用了CopyOnWriteArrayList作为介质
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
private static final long serialVersionUID = 5457747651344034263L;
private final CopyOnWriteArrayList<E> al;
/**
* Creates an empty set.
*/
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
....
}
CopyOnWrite容器即写时复制的容器,当往容器里添加元素时,并不是直接添加元素到容器里,而是先复制一个新的容器,再往里面添加元素,添加完元素后,再将原容器的引用指向新容器,往容器里添加元素是,要使用加锁机制,否则会创建出多个容器。CopyOnWrite也是一种读写分离的思考,读写不同的容器。
Vector与Hashtable类似,均是对方法进行加锁,保证线程安全源码如下
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public synchronized void copyInto(Object[] anArray) {
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
/**
* Trims the capacity of this vector to be the vector's current
* size. If the capacity of this vector is larger than its current
* size, then the capacity is changed to equal the size by replacing
* its internal data array, kept in the field {@code elementData},
* with a smaller one. An application can use this operation to
* minimize the storage of a vector.
*/
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}
....
}
StringBuffer和StringBuilder的区别
StringBuffer是线程安全的,通过过synchronized对方法进行加锁。
两者均是继承与AbstractStringBuilder,能够避免使用'+'创建很多的Strng型对象。
@Override
public synchronized int length() {
return count;
}
@Override
public synchronized int capacity() {
return value.length;
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);
}