首页 > 关于线程安全List读时加锁的问题

关于线程安全List读时加锁的问题

Vector或Collections.synchronizedList为什么get方法要加锁?CopyOnWriteArrayList并没有。
我觉得读的时候不加锁应该没问题吧?读时候加锁有什么意义?能确保读到最新值?那么直接给Object[] elementDatavolatile关键字保证可见性。
我也知道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,在读上不加,并不单单有读不到最新值的问题,更大的问题还是线程工作内存与主存的同步,设想下面的情况:

  1. 整数i = 0

  2. a线程给i + 1

  3. 在a执行这个+1操作的同时b线程读i到自己的工作内存,此时i仍然是0,因为没有给读加锁

  4. a线程执行完毕,i = 1,然后同步到主存

  5. b对i做+1操作,由于a已释放了写锁,b可以写,但由于自己工作内存的i是0,所以+1后i还是1

  6. b操作完毕,同步到主存,主存的i还是1。但事实上希望i是2

【热门文章】
【热门文章】