2008-09-17 5 views
10

ist es legal für einen Thread, this.start() in seinem eigenen Konstruktor aufzurufen? und wenn ja, welche potenziellen Probleme kann dies verursachen? Ich verstehe, dass das Objekt nicht vollständig initialisiert wurde, bis der Konstruktor vollständig ausgeführt wurde, aber abgesehen davon gibt es andere Probleme?Aufruf von thread.start() innerhalb eines eigenen Konstruktors

Antwort

1

Es ist legal, aber nicht klug. Der Thread-Teil der Instanz wird vollständig initialisiert, der Konstruktor jedoch nicht. Es gibt sehr wenig Grund, Thread zu erweitern, und Tricks zu ziehen, wird Ihrem Code nicht helfen.

2

Ich nehme an, dass Sie dies tun möchten, um Ihren Code weniger ausführlich zu machen; anstatt zu sagen

Thread t = new CustomThread(); 
t.start(); 
activeThreads.add(t); 

können Sie einfach sagen

activeThreads.add(new CustomThread()); 

Ich mag auch weniger Ausführlichkeit zu haben, aber ich stimme mit den anderen Befragten, die Sie nicht tun sollten. Insbesondere bricht es die Konvention; Wer mit Java vertraut ist und das zweite Beispiel liest, geht davon aus, dass der Thread nicht gestartet wurde. Schlimmer noch, wenn sie ihren eigenen Threading-Code schreiben, der in irgendeiner Weise mit Ihrem interagiert, dann müssen einige Threads start aufrufen und andere nicht.

Dies scheint nicht zwingend, wenn Sie alleine arbeiten, aber irgendwann müssen Sie mit anderen Menschen arbeiten, und es ist gut, gute Programmiergewohnheiten zu entwickeln, so dass Sie eine einfache Zeit mit anderen arbeiten und Code geschrieben mit den Standardkonventionen.

Wenn Sie jedoch die Konventionen nicht mögen und die zusätzliche Ausführlichkeit hassen, dann gehen Sie vor; Dies führt zu keinen Problemen, auch wenn Sie versehentlich versuchen, start aus Versehen aufzurufen.

2

By the way, wenn eine untere Ausführlichkeit will und immer noch den Konstruktor mit der "Standard" Semantik halten, könnte man eine Factory-Methode erstellen:

activeThreads.add(CustomThread.newStartedThread()); 
+0

Wie ist das relevant für die Frage des OP? – subsub

1

Es ist "legal", aber ich denke, Das wichtigste Problem ist das: Eine Klasse sollte eine Sache tun und es gut machen.

Wenn Ihre Klasse intern einen Thread verwendet, sollte das Vorhandensein dieses Threads in der öffentlichen API nicht sichtbar sein. Dies ermöglicht eine Verbesserung ohne Beeinträchtigung der öffentlichen API. Lösung: Erweitern Sie Runnable, nicht Thread.

Wenn Ihre Klasse allgemeine Funktionalität bietet, die in diesem Fall in einem Thread ausgeführt wird, dann möchten Sie sich nicht auf immer beschränken, indem Sie einen Thread erstellen. Die gleiche Lösung hier: Runnable erweitern, nicht Thread.

Für weniger Ausführlichkeit Ich zweite den Vorschlag, eine Factory-Methode (z. B. Foo.createAndRunInThread()) zu verwenden.

13

Aus Gründen der Speichersicherheit sollten Sie keinen Verweis auf ein Objekt oder die Felder dieses Objekts einem anderen Thread innerhalb seines Konstruktors zugänglich machen. Wenn Sie davon ausgehen, dass Ihr benutzerdefinierter Thread über Instanzvariablen verfügt, können Sie, indem Sie ihn innerhalb des Konstruktors starten, die Java Memory Model-Richtlinien verletzen. Siehe Brian Goetz's Safe Construction Techniques für weitere Informationen.

+1

Kommentare zu dieser Antwort? Es ist nicht falsch. –

+1

Downvote? Bitte geben Sie eine Quelle an, wenn Sie denken, dass dies falsch ist. Das ist richtig. –

+0

Die Antwort ist überhaupt nicht in Ordnung. Wenn Sie den Runnable-Konstruktor nicht verwenden, können Sie 'this' in' Thread # run' referenzieren, bevor der Konstruktor abgeschlossen wird, was gegen die Sicherheitsregeln des Speichers verstößt. Daher müssen Sie vorsichtig sein. –

3

Sie werden auch seltsame Probleme sehen, wenn die Thread-Klasse immer weiter unterklassiert wird. In diesem Fall wird der Thread bereits nach dem Beenden von super() ausgeführt, und alles, was die Unterklasse in ihrem Konstruktor tun könnte, könnte ungültig sein.

@bill barksdale Wenn der Thread bereits ausgeführt wird, erhalten Sie durch einen Aufruf von start erneut eine IllegalThreadStateException, Sie erhalten keine 2 Threads.

1

Legal ... ja (mit Einschränkungen wie an anderer Stelle erwähnt). Ratsam ... nein.

Ich bin nur ein Geruch, den Sie nur zu leicht vermeiden können. Wenn Sie möchten, dass Ihr Thread automatisch startet, tun Sie es einfach wie 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(); 
    } 
    } 
}