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의 각 스레드에는 자체 작업 메모리가 있으며 이는 주 메모리의 복사본으로 이해될 수 있습니다. 휘발성을 사용하는 경우 주 메모리에서 즉시 읽을 수 있다는 것만 보장할 수 있으며 각 스레드의 작업 메모리와의 원자적 동기화를 보장할 수 없습니다.
휘발성을 사용하지 않고 쓰기 작업에만 동기화를 추가하고 읽기 작업에는 추가하지 않더라도 최신 값을 읽을 수 없다는 문제뿐만 아니라 더 큰 문제는 동기화입니다. 스레드 작업 메모리와 주 메모리의 다음 상황을 상상해 보세요.
정수 i = 0
스레드는 i + 1을 제공합니다
a가 이 +1 작업을 수행하는 동안 스레드 b는 i를 자체 작업 메모리로 읽어 들입니다. 이때 읽기가 잠겨 있지 않기 때문에 i는 여전히 0입니다.
스레드 실행 완료, i = 1, 그리고 메인 메모리에 동기화
b는 i에 대해 +1 작업을 수행합니다. a가 쓰기 잠금을 해제했으므로 b는 쓸 수 있지만 자체 작업 메모리의 i는 0이므로 +1 이후에도 여전히 1입니다.
b 작업이 완료되어 주 메모리에 동기화됩니다. 주 메모리의 i는 여전히 1입니다. 하지만 사실 난 2살이었으면 좋겠다