Vector或Collections.synchronizedList为什么get方法要加锁?CopyOnWriteArrayList并没有。
我觉得读的时候不加锁应该没问题吧?读时候加锁有什么意义?能确保读到最新值?那么直接给Object[] elementData
加volatile
关键字保证可见性。
我也知道CopyOnWriteArrayList修改是每次重新建一个elementData
,但就算不是重新建,读时不加锁有什么问题?请赐教。
//以下是CopyOnWriteArrayList的代码:
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
/**
* {@inheritDoc}
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
return get(getArray(), index);
}
//以下是Vector的代码:
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
Java里面每个线程都有自己的工作内存,你可以理解成主内存的一部分拷贝。如果用volatile,只能保证在主内存上是即时可读的,无法保证与每个线程的工作内存的原子性同步
即便不用volatile,而只是在写操作上加synchronized,在读上不加,并不单单有读不到最新值的问题,更大的问题还是线程工作内存与主存的同步,设想下面的情况:
整数i = 0
a线程给i + 1
在a执行这个+1操作的同时b线程读i到自己的工作内存,此时i仍然是0,因为没有给读加锁
a线程执行完毕,i = 1,然后同步到主存
b对i做+1操作,由于a已释放了写锁,b可以写,但由于自己工作内存的i是0,所以+1后i还是1
b操作完毕,同步到主存,主存的i还是1。但事实上希望i是2