2013-11-14 2 views
2

Я читал параллелизм в действии и имел пару вопросов.Безопасность нити/публикация

public final class ThreeStooges { 

    private final Set<String> stooges = new HashSet<String>(); 

    public ThreeStooges() { 
     stooges.add("Moe"); 
     stooges.add("Larry"); 
     stooges.add("Curly"); 
    } 

    public boolean isStooge(String name) { 
     return stooges.contains(name); 
    } 
} 

В книге говорится, что, поскольку этот класс является неизменяемым это поточно, так как нет никакого изменения состояния (Stooges). Я смущен этим. Что делать, если несколько потоков должны были вызвать метод isStooge (String name) одновременно. Что происходит?

public class HolderObject{ 

    private 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."); 
    } 
} 

То же самое и с этим. Что с этим не так? Что делать, если несколько потоков звонят assertSanity().

Спасибо ребята

UPDATE

Скажем, класс приспешники изменяется на следующий ...

public class ThreeStooges { 

private List<String> stooges = new ArrayList<String>(); 

public ThreeStooges() { 
    stooges.add("Moe"); 
    stooges.add("Larry"); 
    stooges.add("Curly"); 
} 

public synchronized void addStoog(String stoog){ 
     stooges.add(stoog); 
} 

public boolean getStoog(int index){ 
    return stooges.get(index); 
} 

public boolean isStooge(String name) { 
    return stooges.contains(name); 
} 
} 

Есть ли какие-либо проблемы нить здесь? Проблемы с видимостью на геттерах? Если поток A был для addStoog («Bobby») и Thread B вызывает getStoog (3), будет ли последний мачеха видна на геттере?

ответ

2

Что делать, если несколько потоков должны были вызвать метод isStooge (String name) одновременно. Что происходит?

В модели памяти Java у вас возникают проблемы, если два потока обращаются к одним и тем же данным одновременно и по крайней мере один из них является записью. Это называется conflicting access.

В этом примере у вас есть несколько потоков, обращающихся к тем же данным (переменная stooges), но ни одна из них не изменяет данные, поэтому вы в порядке.

В книге говорится, что это не потолочный сейф? Зачем? Что значит, что он не опубликован должным образом?

В этом случае, однако, вы назначаете новое значение holder, что является записью. Это гонка данных, если два потока звонят initialize в то же время без внешней синхронизации, произойдут плохие вещи.

Термин «опубликованный», скорее всего, относится к тому, как изменение, сделанное в одном потоке, становится видимым для других потоков. Хотя я не признаю это как общий термин, поэтому, я думаю, книга должна дать точное определение термина в какой-то момент.

То же самое и с этим. Что с этим не так? Что делать, если несколько потоков вызывают assertSanity().

Как вы его разместили, код кажется прекрасным. Поскольку assertSanity только читает n, у вас нет гонки данных.

Однако, как указано в ответе @ EnnoShioji, может возникнуть проблема, когда потоки соблюдают неинициализированное значение n, и, следовательно, казалось бы, тривиальная проверка может завершиться неудачей.

1

Я согласен с первым ответом @ComicSansMS, но я думаю, что его третий ответ не относится к исходной точке книги.

Этот раздел книги (Java Concurrency in Practice) говорит о безопасной публикации. Объект, неизменяемый, автоматически не означает, что он свободен от проблемы параллелизма (в данном случае видимость проблема). Несмотря на то, что состояние Holder не изменяется в течение его жизненного цикла, если к нему обращается другой поток, не удовлетворяющий некоторым правилам, другой поток может видеть конструкцию середины объекта и, следовательно, видеть неправильные значения.

Потому что, когда объект построен, поля сначала заполняется нуль/нуль, в третьем примере (Holder), поток мог видеть n=0, а затем n=42, и, следовательно, бросить AssertionError.

Вот что значит, что книга, когда он говорит:

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

Если бы вы указали поле int как final, объект Holder стал бы формально «неизменным объектом», и поэтому JMM гарантировала бы, что такого состояния гонки не произойдет (см. Параграф о специальной гарантии на неизменяемый объекты). В книге также описаны другие правила, которые вы можете соблюдать, чтобы это не происходило.

+0

Оба вы, ребята, были большой помощью, но я не могу отметить оба. Я также не могу повышать, потому что у меня меньше 15 человек. – user1172490

+0

+1 И спасибо за объяснение третьего примера. Один следующий вопрос здесь: может ли эта гонка все же произойти, если есть связь между вызовом конструктора 'Holder' и вызовом функции' assertSanity'? Я спрашиваю, потому что в общем случае, если у вас есть расы между завершением выполнения конструктора и вызовами функций-членов, у вас обычно возникают еще большие проблемы, поскольку инварианты класса могут быть не установлены при выполнении функций-членов. – ComicSansMS

+1

Я думаю, что по спецификации Java 5 модель памяти изменилась, чтобы позволить конструктору полностью закончить, прежде чем можно будет вызвать другие методы.Я не знаю, если я на 100% прав. Здесь нужен эксперт. – user1172490

0

Один простой способ думать о Java параллелизм заключается в следующем:

  • Каждая тема имеет копию переменной.
  • Если синхронизация Java (volatile, locks, synchronized) не используется, Thread может никогда не «получить» новую копию переменной, а в случае «set» она никогда не сможет очистить значение до основной переменной.

В вашем примере, вы заставляете «сеттер», чтобы получить блокировку на объекте и промывать новое значение основной переменной, используя synchronized ключевое слово: synchronized void addStoog

С другой стороны, вы не заставляя «получателей» получить новую копию stooges, что приведет к чтению несогласованных данных.

Смежные вопросы