Могу ли я запустить поток из конструктора? - PullRequest
3 голосов
/ 12 мая 2009

Учитывая модель памяти J5 + (JSR-133), является ли следующий код потокобезопасным и допустимым?

А если это безопасно, приемлемо ли это в некоторых ситуациях?

public final class BackgroundProcessor
extends Object
implements Runnable
{

public BackgroundProcessor(...) {
    super();

    ...

    new Thread(this).start();
    }

public void run() {
    ...
    }
}

Когда я читаю новую спецификацию JMM, инициирование потока создает отношение «происходит до того» со всем, что делает инициированный поток.

Предположим, что объект имеет закрытые переменные-члены, установленные в конструкторе и используемые в run ().

И класс помечается как окончательный, чтобы избежать неожиданностей подклассов.

Примечание: здесь есть похожий вопрос, но он имеет другой угол: вызов thread.start () в своем собственном конструкторе

Ответы [ 3 ]

4 голосов
/ 12 мая 2009

JLS: потоки и блокировки говорит

Два действия могут быть упорядочены по отношениям "до того как случится". Если одно действие происходит раньше другого, то первое видно и упорядочено до второго.

Если у нас есть два действия x и y, мы пишем hb (x, y), чтобы указать, что x происходит до y.

  • Если x и y являются действиями одного и того же потока и x предшествует y в программном порядке, то hb (x, y).

и

Вызов функции start () в потоке происходит до любых действий в запущенном потоке.

, поэтому мы можем сделать вывод, что все действия в конструкторе до вызова Thread.start () происходят до всех действий в потоке, который был запущен. Если Thread.start () в конце концов выполняет запись в поля объекта, тогда запущенный поток будет видеть все записи в поля объекта. Если нет других записей в поля (которые будет читать другой поток), то этот код является потокобезопасным.

3 голосов
/ 12 мая 2009

Ну, если вы не хотите особенно не соглашаться с Брайаном Гетцем по вопросу параллелизма Java, я бы предположил, что это неправильно. Хотя его точные слова "лучше не ...", я все равно прислушаюсь к его совету. От JCIP, стр. 42:

"A распространенная ошибка , которая может позволить «этот» эталонный побег во время конструкция должна начать поток из конструктора [...] Есть ничего плохого в том, что создает поток в конструкторе, но лучше не начать поток немедленно. Вместо этого выставьте начало или инициализируйте метод ... "

Обновление: просто для подробного объяснения, почему это проблема. Хотя между вызовом Thread.start () и тем методом run (), который фактически начинает выполняться, гарантированный барьер памяти существует, такого барьера между тем, что происходит во время конструктора после вызова Thread, не существует. .Начните(). Таким образом, если некоторые другие переменные все еще должны быть установлены, или если JVM выполняет некоторую служебную работу «просто-только-построенный-объект», ни одна из них не гарантированно будет замечена другим потоком: то есть объект может быть виден другой поток в неполном состоянии.

Между прочим, помимо того, действительно ли он ломает JMM, он также выглядит как «странная вещь» в конструкторе.

0 голосов
/ 12 мая 2009
  1. Ваш класс, вероятно, должен реализовывать Runnable

  2. Да, ваш код в порядке

  3. Нет необходимости расширять объект. Я уверен, что вы знаете, что Object расширяется неявно всеми классами. Я не знаю, откуда эта популярная практика явного расширения объекта, но это плохой стиль.

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