在下面的hypotetical场景中,出于更好地理解语言的愿望, int [] 引用需要volatile吗?
public final class SO {
private int[] ar = new int[10]; // is volatile needed here?
private int idx = 0;
public synchronized int get( int i ) {
return ar[i];
}
public synchronized void append( final int val ) {
if ( idx == ar.length ) {
// array is too small, let's grow it
final int[] prev = ar;
ar = new int[ar.length+ar.length*20/100]
System.arrayCopy(prev, 0, ar, 0, prev.length);
}
ar[idx++] = val;
}
}
检索 int 的唯一方法是通过 synchronized 方法和修改 int [] 的唯一方法(包括创建一个new int [] )也是通过同步方法完成的。
我不需要添加任何其他同步吗?
答案 0 :(得分:3)
不,volatile
不需要,因为它只在同步方法中访问,所以它已经是线程安全的。您的代码不需要进一步的线程安全。
答案 1 :(得分:2)
它会像你说的那样,因为int受类锁保护 - 但它会慢,因为写和读访问相互阻塞。 (以更快的方式参见CopyOnWriteList实现)
答案 2 :(得分:1)
你很好,除非你的值在没有同步的情况下访问其他地方。
顺便说一下,如果您确实使用ar
volatile
而不是使用同步方法,则还需要使idx
变为易变。但是仍然没有足够的同步,因为同时运行append
的两个不同线程可能会造成严重破坏。
实际上,使用volatile
数组还有另一个问题:更改数组中的值不会触发缓存同步。只重新分配数组(就像创建更大的数组时一样)会触发缓存刷新。
答案 3 :(得分:1)
根据 java lang specfication 使用volatile为线程添加严格的规则(从主内存读/写),使用synchronized稍微放松一下。