2016-08-20 8 views
0

Рассмотрим фрагмент кода Java Параллелизм в Practice-Немного прояснение летучим ключевое слово

// Unsafe publication 
public Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

public class Holder{ 
    private int n; 

    public Holder(int n) { 
     this.n = n; 
    } 

    public void assertSanity(){ 
     if (n != n) 
      throw new AssertionError("This statement is false."); 
    } 
} 

Одним из решений, предложенных автором книги -

public static Holder holder = new Holder(42); 

И если единственное требование состояло в том, чтобы предотвратить AssertionError, тогда это также будет работать нормально

private final int n; 

Мой вопрос прослеживание на комментарий по этому StackOverflow thread Джон Vint-

На самом деле, объявляя поле член летучего еще оленья кожа гарантировать публикации до держателя быть видны. Вы можете посмотреть на Частный метод ConcurrentHashMap readUnderLock, в котором это учитывает этот нюанс . Хотя объявление держателя как изменчивое.

Выражаясь простыми словами, он предлагает, тем самым 2 вещей:

public volatile Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

ли вышеуказанное решение будет работать отлично? Если ссылка на объект объявлена ​​изменчивой, обеспечивает ли она безопасную публикацию объекта? Массивы тоже объекты. Объявление ссылки на массив не делает потоки элементов безопасными.

И почему это не будет работать, как было предложено

автора
public class Holder { 
private volatile int n; 

объявления поля члена летучей еще оленья кожа гарантии публикации до держателя быть видимый

Несмотря на то, как член поле было объявлено летучим, его гарантируют, что условие n != n будет всегда false, и, следовательно, нет AssertionError. Пожалуйста, предложите.

ответ

2

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

Если ссылка на объект объявлена ​​изменчивой, обеспечивает ли он безопасную публикацию объекта?

Это очень зависит от порядка и типа операций.В этом случае, запись

this.n = n; 
// and then 
holder = ... 

Запись в holder обеспечить записываемый в this.n должен быть видны при условии, вы также

Holder h = holder; // read barrier 
// n must be set. 
int n = this.n; 

объявления поля члена летучей еще оленья кожа гарантии публикации до держателя являющийся видимым

В данном случае я не согласен. Как только вы получили holder в другом потоке, нет никакой вероятности, что чтение n не сможет увидеть значение, инициализированное при чтении изменчивой переменной. Это связано с тем, что holder установлен только после инициализации n.

+0

Спасибо. Но автор не ошибается в этом конкретном случае. –

+0

@ShirgillFarhanAnsari Я согласен, в целом 'volatile' не предоставляет вам необходимые гарантии, но в этом конкретном случае это будет работать. –

+0

Еще раз спасибо, но не получил вашу точку за второй фрагмент кода 'Holder h = holder;' // читаем барьер. Пожалуйста, дополните. –

0

Попробуйте

public class main { 
public volatile static Holder holder; 
public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    // Unsafe publication 
    initialize(); 
    holder.assertSanity(99); 
} 
public static void initialize(){ 
    holder = new Holder(42); 
} 
} 

Holder.java

public class Holder { 

private volatile Integer n; 
    public Holder(Integer n) { 
     this.n = n; 
    } 

    public void assertSanity(Integer n){ 
     if (!((Object)this.n).equals((Object)n)) 
      throw new AssertionError("This statement is false."); 
    } 

    public Integer getN() { 
     return n; 
    } 

    public void setN(Integer n) { 
     this.n = n; 
    } 

}