1.什么是线程安全
在一个进程中可能会有多个线程,多个线程访问同一个对象时,在主程序内不需要做任何同步操作,或者在调用方法内进行其他的协调操作,调用这个对象的结果行为都是正确的,此时这个对象就是线程安全的。
2.引起线程不安全的原因
对于线程间共享数据的更改操作会导致结果错误。
3.线程不安全的解决策略
使共享数据在多线程情况下保持正确的取值。
4.java中线程安全的类
- Vector
- HashTable
- ConcurrentHashMap
- StringBuffer
- Properties
Stack
- .....
5.线程不安全的类
- ArrayList
- LinkedList
- HashMap
- HashSet
- TreeMap
- TreeSet
- StringBulider
对于Vector源码
public synchronized void insertElementAt(E obj, int index) {
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
modCount++;
final int s = elementCount;
Object[] elementData = this.elementData;
if (s == elementData.length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = obj;
elementCount = s + 1;
}
public synchronized void addElement(E obj) {
modCount++;
add(obj, elementData, elementCount);
}
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
public synchronized void removeAllElements() {
final Object[] es = elementData;
for (int to = elementCount, i = elementCount = 0; i < to; i++)
es[i] = null;
modCount++;
}
vector许多操作都是加了synchronized修饰的,例如插入,增加,移除。
对于HashTable源码,
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;
}
其他添加synchronized修饰的方法,size(),isEmpty(),keys()等等
对于ConcurrentHashMap
ConcurrentHashMap实现线程安全也是通过synchronized关键字来控制代码同步来实现的,不同于HashTable的是ConcurrentHashMap在线程同步上更加细分化,它不会像HashTable那样一把包揽的将所有数据都锁住,而是采用分段锁的思路。
对于ConcurrentHashMap和HashTable
HashTable和ConcurrentHashMap都是线程安全的容器。
- HashTable: 线程安全,效率和容器的大小成正比。容器数据量越大,效率越慢
- ConcurrentHashMap: 线程安全,效率相对于不如HashMap,但是和HashTable相比,效率得到很大的提升。
综合考虑,如果使用线程安全容器,推荐使用ConcurrentHashMap
对于StringBuffer源码
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
所有的方法也是使用synchronized修饰确保线程安全。