2012-01-19 5 views
1

В следующем гипотетическом сценарии и из желания лучше понять язык, является летучим, необходимым для int [] ссылка?Неувядаем здесь?

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 является корытом синхронизированного метода и единственным способом изменить Int [] (включая создание нового Int []) также делается желоб синхронизированный метод.

Мне не нужно добавлять дополнительную синхронизацию справа?

+0

Вы отметили это как примитивное, но на самом деле int [] является объектом, поскольку он представляет собой массив java. – wmorrison365

+0

Выполнение 'ar' volatile только присваивает' ar' (не элемент внутри него) volatile write –

+0

'ar.length + ar.length * 20/100' =' ar.length * 6/5' –

ответ

3

Нет, volatile не требуется, поскольку он доступен только внутри синхронных методов, поэтому он уже является потокобезопасным. В вашем коде не требуется дополнительная безопасность потока.

2

это будет так, как вы сказали, так как int защищен блокировкой класса - но это будет собака медленная, так как запись и чтение блокируют друг друга. (см. реализацию CopyOnWriteList для более быстрого способа)

+0

Я не знаю, является ли «блокировка класса» принятым термином, но он предлагает один замок для всех экземпляров. Где это эквивалентно «синхронизированному (это) {...}' блоку. – weston

+1

Я думаю, что чаще всего аннотировать свойство с помощью @GuardedBy («this»), чтобы сделать его более понятным. Таким образом, это скорее объявление уровня класса, чем уровень объекта, которому вы передаете объект для блокировки. –

1

Вы в порядке, если только ваши значения не доступны в другом месте без синхронизации.

Кстати, если вы использовали arvolatile вместо того, чтобы использовать синхронизированные методы, вам нужно будет также сделать idx. Но этого было бы недостаточно для синхронизации, потому что два разных потока, запущенных append, могут нанести ущерб хаосу.

На самом деле есть еще одна проблема с использованием массива volatile: изменение значения в массиве не вызывает синхронизацию кэша. Только переназначение массива (как вы делаете при создании большего массива) запускает кеш-флеш.

1

В соответствии с java lang specfication с изменчивым добавлением строгих правил для потоков (чтение/запись из основной памяти) с использованием синхронизированных релаксаций на этом немного.