Построение Java-объектов в многопоточной среде - PullRequest
5 голосов
/ 07 июня 2011

Я читаю эту книгу под названием «Параллелизм Java на практике», и автор приводит пример публикации небезопасных объектов.Вот пример.

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

Значит ли это, что другой поток имеет доступ к объекту, когда он даже не полностью построен?Я предполагаю, что когда поток A вызывает holder.initialize();, а поток B вызывает holder.assertSanity();, условие n != n не будет выполнено, если поток A еще не выполнен this.n = n;

Означает ли это также, что если яиметь более простой код, такой как

int n;

System.out.println(n == n); //false?

Ответы [ 3 ]

3 голосов
/ 07 июня 2011

Проблема может возникнуть, если метод assertSanity будет переопределен между первой и второй загрузкой n (первая загрузка будет видеть 0, а вторая загрузка будет видеть значение, установленное конструктором). Проблема в том, что основными операциями являются:

  1. Выделить место для объекта
  2. Позвоните конструктору
  3. Установить holder для нового экземпляра

Компилятору / JVM / CPU разрешено переупорядочивать шаги # 2 и # 3, поскольку нет никаких барьеров памяти (конечных, энергозависимых, синхронизированных и т. Д.)

Из вашего второго примера неясно, является ли "n" локальной переменной или переменной-членом, или как другой поток может одновременно изменять ее.

1 голос
/ 07 июня 2011

Ваше понимание верно.Именно эту проблему автор пытается проиллюстрировать.В Java нет средств защиты, которые гарантируют, что объект полностью создан до доступа, когда речь идет о нескольких потоках.Держатель не является потокобезопасным, поскольку содержит изменяемое состояние.Чтобы исправить это, необходимо использовать synchronization.

Я не уверен, что понимаю ваш второй пример, в нем отсутствует контекст.

0 голосов
/ 06 августа 2014
public static void main(String[] args) {

    A a = new A();
    System.out.println(a.n);

}

static class A{
    public int n;

    public A(){

        new Thread(){

            public void run() {
                System.out.println(A.this.n);
            };

        }.start();

        try {
            Thread.currentThread().sleep(1000);
            n=3;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

В этом примере результат «0 3» означает, что ссылка на объект может использоваться другим потоком еще до того, как его конструктор завершит работу. Остальные вы можете найти здесь .Хотелось бы, чтобы это помогло.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...