# Threads in Sequenzdiagramm darstellen



## inthemiddle (14. Jan 2021)

Hi, wie kann ich denn Threads in einem Sequenzdiagramm darstellen?

```
Thread th = new Thread(() -> {c.g(11, A.this);});
        th.start();
```

th.start() ist ja ein ganz normaler Methodenaufruf, wird denn dann der Thread in einem Rechteck (wie ein Objekt) th:Thread dargestellt?


----------



## fhoffmann (14. Jan 2021)

Wichtig ist hier doch, dass die Methode `g` auf dem Objekt `c` aufgerufen wird. Dass dies in Java mit Hilfe eines Objects der Klasse `Thread` geschieht, ist ein Implementierungsdetail.


----------



## inthemiddle (14. Jan 2021)

Also bräuchte ich das gar nicht darzustellen?


----------



## fhoffmann (14. Jan 2021)

inthemiddle hat gesagt.:


> Also bräuchte ich das gar nicht darzustellen?


Das ist Geschmackssache - und ich kenne den Geschmack deines Profs nicht.


----------



## mihe7 (14. Jan 2021)

Was man ohne Implementierungsdetails darstellen kann, ist dass c.g() asynchron aufgerufen wird.


----------



## fhoffmann (14. Jan 2021)

inthemiddle hat gesagt.:


> Thread th = new Thread(() -> {c.g(11, A.this);});


Dieser Code bedeutet ja eigentlich
- dass du eine anonyme Klasse erstellst, die von java.lang.Thread erbt,
- dass du die Methode run() überschreibst
Die Methode run() wird von der Methode start() aufgerufen. Und die Methode run() ruft dann c.g() auf.

Wenn das Sequenzdiagramm dazu dienen soll, den Ablauf des Codes zu verstehen, würde ich solche Details nicht darstellen (außer - wie mihe7 es erwähnt hat - die Tatsache, dass der Aufruf asynchron ist).

Wenn das Sequenzdiagramm allerdings dazu dienen soll, zu überprüfen, ob du verstanden hast, wie in Java Threads arbeiten, müssen die Details natürlich enthalten sein.


----------



## mrBrown (14. Jan 2021)

fhoffmann hat gesagt.:


> Dieser Code bedeutet ja eigentlich
> - dass du eine anonyme Klasse erstellst, die von java.lang.Thread erbt,
> - dass du die Methode run() überschreibst
> Die Methode run() wird von der Methode start() aufgerufen. Und die Methode run() ruft dann c.g() auf.


Ne, überschrieben wird Thread dort nicht, es wird nur ein Runnable übergeben, welches dann vom Thread innerhalb von run ausgeführt wird


----------



## fhoffmann (14. Jan 2021)

mrBrown hat gesagt.:


> Ne, überschrieben wird Thread dort nicht, es wird nur ein Runnable übergeben, welches dann vom Thread innerhalb von run ausgeführt wird


Hallo mrBrown,

ich hatte auch überlegt, ob dies so sein könnte. Aber das schien mir zu kompliziert. Was ist den der Vorteil dieser Konstruktion ?
Ich müsste ja etwa folgenden Code generieren:

```
class AnonymRunnable implements Runnable {
  public void run() {
    // doSomething()
  }
}
AnonymRunnable anonymRunnable = new AnonymRunnable();
Thread thread = new Thread(anonymRunnable);
```
Dagegen ist es doch einfacher, folgenden Code zu generieren:

```
class AnonymThread extends Thread {
  public void run() {
    // doSomething()
  }
}
Thread thread = new AnonymThread();
```


----------



## mrBrown (14. Jan 2021)

Wieso Code generieren, der fertige, ausführbare Code steht doch bereits dort?

Die Übergabe eines Runnables passt in den meisten Fällen schon aus semantischen Gründen besser: der eigene Code soll zwar in einem Thread ausgeführt werden, ist aber kein Thread.
Außerdem kann man mit Runnables besser arbeiten:  Thread zu erweitern koppelt einen an die Thread-Klasse, in vielen Fällen will man aber gar nicht explizit selbst einen Thread starten, sondern viel eher ExecutorServices und ThreadPools nutzen - das ist mit Runnables direkt möglich. Wenn nötig, kann man dabei immer noch explizit den Thread erzeugen, hat aber deutlich mehr Möglichkeiten.


----------



## mihe7 (14. Jan 2021)

fhoffmann hat gesagt.:


> Was ist den der Vorteil dieser Konstruktion ?


Z. B. dass man mit Lambdas arbeiten kann


----------



## fhoffmann (14. Jan 2021)

mihe7 hat gesagt.:


> Z. B. dass man mit Lambdas arbeiten kann


Und erben (implementieren) Lambdas immer von java.lang.Runnable ?
sorry -aber ich habe mich mit der Theorie von Lambdas noch nicht beschäftigt.


----------



## mrBrown (14. Jan 2021)

fhoffmann hat gesagt.:


> Und erben Lambdas immer von java.lang.Runnable ?
> sorry -aber ich habe mich mit der Theorie von Lambdas noch nicht beschäftigt.


Ne, die können jedes Single-Abstract-Method-Interface implementieren – welches das konkret ist, ist erst durch den "Zieltyp" klar.

Stumpf ausgedrückt sind Lambdas die Reduktion der Implementierung einer normalen Klasse, die das Interface erweitert, auf das minimal nötige: 

```
class AnonymRunnable implements Runnable {
  public void run() {
    // doSomething()
  }
}
```

- Klassenname ist egal, Lambdas sind anonym, kann also weg
- das Implementierte Interface ist durch die Nutzung auch eindeutig
- Signatur und Rückgabetyp der Methode sind auch klar, da das Interface nur eine Methode hat, wichtig sind nur Parameter

Wenn man das alles weg lässt, landet man für Runnable bei:

```
() -> {}
```


----------



## mihe7 (14. Jan 2021)

fhoffmann hat gesagt.:


> Und erben Lambdas immer von java.lang.Runnable ?
> sorry -aber ich habe mich mit der Theorie von Lambdas noch nicht beschäftigt.


Nein. Lambdas sind anonyme Funktionen (analog zu anonymekn Klassen). Du kannst sie überall verwenden, wo ein functional interface erwartet wird, also ein Typ mit genau einer zu implementierenden Methode.

Runnable hat nur eine Methode `void run()` daher kannst Du ein Runnable mit einem Lambda implementieren: `() -> { .... }` vorne steht die Parameterliste der Methode.

EDIT: Halte Dich an die Beschreibung von @mrBrown - die ist wesentlich besser.


----------



## fhoffmann (14. Jan 2021)

Besten Dank für eure Informationen.

Nach diesem kurzen Abschweif können wir ja wieder auf die ursprüngliche Frage (Sequenzdiagramme) zurückkommen.


----------



## fhoffmann (14. Jan 2021)

Ich habe gerade noch einaml darüber nachgedacht:

Die Klasse Thread
- implementiert das interface Runnable
- und hat ein Member vom Typ Runnable

Wenn ich also

```
Thread th = new Thread(() -> {c.g(11, A.this);});
```
aufrufe, müsste die Methode run() des interfaces Runnable aufgerufen werden, das Thread implementiert, und nicht die Methode des Members.


----------



## mrBrown (14. Jan 2021)

fhoffmann hat gesagt.:


> aufrufe, müsste die Methode run() des interfaces Runnable aufgerufen werden, das Thread implementiert, und nicht die Methode des Members.


Ja, allerdings ruft die run() Methode in Thread die run-Methode des Members auf


----------



## fhoffmann (14. Jan 2021)

mrBrown hat gesagt.:


> Ja, allerdings ruft die run() Methode in Thread die run-Methode des Members auf


Es gibt aber in diesem Fall kein Member (null), also wird die eigene run()-Methode aufgerufen.


----------



## mrBrown (14. Jan 2021)

fhoffmann hat gesagt.:


> Es gibt aber in diesem Fall kein Member (null), also wird die eigene run()-Methode aufgerufen.


In diesem Fall:

```
Thread th = new Thread(() -> {c.g(11, A.this);});
```

Wird doch ein Runnable übergeben, das landet im Member `target`, und in der run-Methode von Thread gibts dann ein 

```
if (target != null) {
    target.run();
}
```
womit dann das übergebene Runnable ausgeführt wird.


----------



## fhoffmann (14. Jan 2021)

fhoffmann hat gesagt.:


> Die Klasse Thread
> - implementiert das interface Runnable
> - und hat ein Member vom Typ Runnable


Und woher weiß Java, ob es die Methode, die implementiert ist (wie ich behaupte), oder die Methode des Members (wie du behauptest) überschreiben bzw. aufrufen soll?


----------



## mrBrown (14. Jan 2021)

Häh?

Beim Starten eines Threads wird immer die run-Methode dieses Threads aufgerufen.
*In* der run-Methode des Threads wird dann die run-Methode des übergebenen Runnables aufgerufen, da ist keinerlei Magie oder so beteiligt.


----------



## fhoffmann (14. Jan 2021)

mrBrown hat gesagt.:


> Häh?


Es ist aber doch auch möglich, dass ich dem Thread kein Runnable übergebe. Dann wird die überschriebene run-Methode aufgerufen.


----------



## mrBrown (14. Jan 2021)

Ja:


mrBrown hat gesagt.:


> Beim Starten eines Threads wird immer die run-Methode dieses Threads aufgerufen.


Wenn man die run-Methode des Threads überschrieben hat, wird eben das überschriebene ausgeführt.


----------



## fhoffmann (14. Jan 2021)

mrBrown hat gesagt.:


> Wenn man die run-Methode des Threads überschrieben hat, wird eben das überschriebene ausgeführt.


Dann verstehe ich aber nicht deine Antwort #7.


mrBrown hat gesagt.:


> Ne, überschrieben wird Thread dort nicht, es wird nur ein Runnable übergeben, welches dann vom Thread innerhalb von run ausgeführt wird


----------



## mrBrown (15. Jan 2021)

Thread sieht ganz grob so aus:


```
class Thread implements Runnable {
    
    Runnable target;
    
    public Thread() {}
    
    public Thread(Runnable target) {
        this.target = target;
    }
    
    public final void start() {
        this.run();
    }
    
    public void run() {
        if (target != null) {
            target.run()
        }
    }
    
}
```


Wenn man Thread erweitert und run überschreibt, wird das übergebene Runnable ignoriert und das ausgeführt, womit man die run-Methode überschrieben hat.

Wenn man Thread nicht erweitert, sondern ein Runnable übergibt, wird das übergebene Runnable ausgeführt.


Oben bezog ich mich auf die zweite Variante, dabei wird nichts überschrieben, sondern das Runnable ausgeführt.


----------



## fhoffmann (15. Jan 2021)

mrBrown hat gesagt.:


> Thread sieht ganz grob so aus:


Das ist mir schon klar.
Ich frage ja nur, ob die eigene run()-Methode überschrieben wird oder ob die run()-Methode des übergebenen Objects vom Typ Runnable aufgerufen wird.
Und ich glaube, dass bei

```
Thread th = new Thread(() -> {c.g(11, A.this);});
```
die eigene Methode run() überscrhieben wird.

Letztlich ist dies eine rein akademische Diskussion - das Ergebnis bleibt das gleiche.


----------



## mrBrown (15. Jan 2021)

fhoffmann hat gesagt.:


> Und ich glaube, dass bei
> 
> ```
> Thread th = new Thread(() -> {c.g(11, A.this);});
> ...


Ne, da wird wirklich nichts überschrieben, es wird einfach nur der Konstruktor aufgerufen, der im Endeffekt die Instanzvariable zuweist, und die run-Methode dieser Instanzvariable wird dann aufgerufen.

Überschrieben wird da nichts, es wird nur das Runnable-Interface in Form des Lambdas "implementiert"


----------



## mihe7 (15. Jan 2021)

fhoffmann hat gesagt.:


> Ich frage ja nur, ob die eigene run()-Methode überschrieben wird


Das scheitert schon daran, dass Du zum Überschreiben erstmal eine (ggf. anonyme) von Thread abgeleitete Klasse erstellen müsstest, was hier nicht der Fall ist. 

Der Code ist äquivalent zu

```
Runnable r = () -> {c.g(11, A.this);}
Thread th = new Thread(r);
```
Somit wird einfach eine neue Instanz der Klasse Thread erstellt.

Um die run-Methode von Thread zu überschreiben, müsstest Du ja etwas haben wie

```
Thread th = new Thread() {
    @Override
    public void run() {
        c.g(11, A.this);
    }
};
```


----------

