является ли законным для потока вызвать this.start() внутри своего собственного конструктора? и если да, то какие потенциальные проблемы могут вызвать это? Я понимаю, что объект не будет полностью инициализирован до тех пор, пока конструктор не завершится, но помимо этого есть другие проблемы?
Вызов thread.start() внутри своего собственного конструктора
Ответ 1
По соображениям безопасности памяти вы не должны выставлять ссылку на объект или эти поля объекта в другой поток из своего конструктора. Предполагая, что ваш пользовательский поток имеет переменные экземпляра, запустив его изнутри конструктора, вы гарантированно нарушите правила модели памяти Java. Для получения дополнительной информации см. Brian Goetz Safe Construction Techniques.
Ответ 2
Вы также увидите wierd проблемы, если класс Thread еще более подклассифицирован. В этом случае вы закончите поток, уже запущенный после выхода super(), и все, что может сделать подкласс в своем конструкторе, может быть недействительным.
@bill barksdale Если поток уже запущен, вызов start снова получает вас IllegalThreadStateException, вы не получаете 2 потока.
Ответ 3
Я предполагаю, что вы хотите сделать это, чтобы сделать ваш код менее подробным; вместо того, чтобы говорить
Thread t = new CustomThread();
t.start();
activeThreads.add(t);
вы можете просто сказать
activeThreads.add( new CustomThread() );
Мне также нравится иметь меньше словесности, но я согласен с другими респондентами в том, что вы не должны этого делать. В частности, это нарушает конвенцию; любой, кто знаком с Java, который читает второй пример, предположит, что поток не запущен. Хуже того, если они пишут собственный код потока, который каким-то образом взаимодействует с вашим, то некоторые потоки должны будут вызывать start
, а другие - нет.
Это может показаться нецелесообразным, когда вы работаете самостоятельно, но в конечном итоге вам придется работать с другими людьми, и хорошо развивать хорошие привычки кодирования, чтобы вам было легко работать с другими людьми и кодом написанных стандартными соглашениями.
Однако, если вы не заботитесь об условностях и не ненавидите лишнюю многословие, тогда продолжайте; это не вызовет никаких проблем, даже если вы попытаетесь вызвать start
несколько раз по ошибке.
Ответ 4
Кстати, если кто-то хочет иметь более низкую многословность и по-прежнему сохраняет конструктор со своей "стандартной" семантикой, можно создать метод factory:
activeThreads.add( CustomThread.newStartedThread() );
Ответ 5
Это законно, но не мудро. Часть потока экземпляра будет полностью инициализирована, но ваш конструктор не может. Существует очень мало оснований для продления Thread, и вытаскивать трюки, подобные этому, не поможет вашему коду.
Ответ 6
Это "законно", но я думаю, что самая важная проблема заключается в следующем: Класс должен делать одно и делать это хорошо.
Если ваш класс использует поток внутренне, то существование этого потока не должно быть видимым в публичном API. Это позволяет улучшить, не затрагивая публичный API. Решение: продлить Runnable, а не Thread.
Если ваш класс обеспечивает общую функциональность, которая в этом случае выполняется в потоке, то вы не хотите ограничивать себя созданием потока. То же решение здесь: расширение Runnable, а не Thread.
За меньшую многословность я второй предлагаю использовать метод factory (например, Foo.createAndRunInThread()).
Ответ 7
Юридический... да (с оговорками, как упоминалось в другом месте). Рекомендуемый... нет.
Я просто запах, которого можно легко избежать. Если вы хотите, чтобы ваш поток автоматически запускался, просто сделайте это как Heinz Kabutz.
public class ThreadCreationTest {
public static void main(String[] args) throws InterruptedException {
final AtomicInteger threads_created = new AtomicInteger(0);
while (true) {
final CountDownLatch latch = new CountDownLatch(1);
new Thread() {
{ start(); } // <--- Like this ... sweet and simple.
public void run() {
latch.countDown();
synchronized (this) {
System.out.println("threads created: " +
threads_created.incrementAndGet());
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
};
latch.await();
}
}
}