Java. Czy wątek po wykonaniu przestaję istnieć ?

0

Witam
Podam taki przykład :
Tworzę klasę, przyjmijmy klasa "A" która jest rozszerzona o klasę "Thread" pochodzącą z Javy. W wewnątrz klasy "A" jest metoda "run()". Kiedy stworzę obiekt klasy "A"
i wywołam metodę "start()" to zawartość metody "run()" będzie wykonywać się nie zależnie od dalszego programu, równocześnie z kolejnymi instrukcjami zawartymi w głównej metodzie "main". Moje pytanie jest takie, czy kiedy wykona się zawartość metody "run()" to wątek przestaje istnieć ? Nie mogę go znowu włączyć poprzez metodę "start()" ? Jak ponownie uruchomić metode start() ?

8

Moje pytanie jest takie, czy kiedy wykona się zawartość metody "run()" to wątek przestaje istnieć ?

Obiekt typu Thread pewnie sobie gdzieś leży, aż go GC nie sprzątnie. Sam wątek natywny pod spodem pewnie się kończy od razu po powrocie z metody Thread.run.

Nie mogę go znowu włączyć poprzez metodę "start()" ? Jak ponownie uruchomić metode start() ?

Dokumentacja metody Thread.start stanowi:

It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

Jeśli chcesz żeby coś się odpaliło dwa razy to możesz np. zrobić pętlę w wątku albo odpalić dwa wątki. Jednak zdecydowanie lepszym rozwiązaniem byłoby użycie długo żyjącego Executora i wrzucanie mu tasków na bieżąco.

2

Do tego co napisał @Wibowit dodam, że należy rozdzielić wątki od współbieżnego działania.
Jeśli próbujesz zrozumieć czym są wątki to Wikipedia jest dobrym wstępem.
Jeśli zastanawiasz się, jak wykonywać wspolbieznie jakieś kawałki kodu to poczytaj o executorach i futures'ach

0

@Wibowit: a tworzenie za każdym razem klasy "A" i odpalenie metody run będzie spowalniało program ?

0

Bardzo ogólne pytanie. To zależy, co ten program robi i jak bardzo daje się zrównoleglić, jakimi zasobami dysponujesz. Miej tez na uwadze, że stworzenie wątku po stronie JVM kosztuje ~1MB, co tez nie pozostaje bez wpływu na resztę programu. Kolejna sprawa - zamiast tworzyć te wątki z ręki, lepiej użyć puli wątków (ExecutorService).

2
plugan300 napisał(a):

@Wibowit: a tworzenie za każdym razem klasy "A" i odpalenie metody run będzie spowalniało program ?

Odpalenie metody Thread.run() nie uruchamia nowego wątku, a logika odpali się w obecnym = brak wielowątkowości. Tylko Thread.start() faktycznie odpala nowy wątek.

4

Weź pod uwagę trzy czynniki:
Pierwszy jest taki że jak zadanie w wątku jest bardzo krótkie to się to nie opłaca - jest to koszt tzw. Context Switch.
Drugi jest taki że mogą być jakieś locki(jeśli wątki używają tych samych zasobów) które też spowalniają działanie wątku.
Trzeci jest taki że jest maksymalna liczba wątków które mogą być odpalone. Jeśli masz 8 rdzeni to 8 wątków może przyspieszyć aplikacje, ale wzrost z 8 do 2000 (jeśli nie śpią przez 99% czasy) już spowolni albo spowoduje error.
Najlepiej stworzyć ExecutorService i wykorzystać że w Javie możesz pobrać liczbę rdzeni
https://examples.javacodegeeks.com/core-java/lang/runtime/get-number-of-processors-with-runtime/
Przy czym trochę to inaczej działa jak masz wątek CPU Intensive a inaczej IO intensive:
https://engineering.zalando.com/posts/2019/04/how-to-set-an-ideal-thread-pool-size.html

0

@Wibowit: to wiem

1
plugan300 napisał(a):

@Wibowit: to wiem

To co chcesz wiedzieć więcej? Jeśli dodanie wielowątkowości przyspieszyło program, to usunięcie jej go spowolni. Dość oczywiste :)

Tworzenie obiektu typu Thread tylko po to, by odpalić na nim metodę run jest bez sensu, a wręcz może wprowadzać w błąd (ktoś pomyśli, że jest wielowątkowość, a jej nie będzie). Obiekt typu Thread coś tam waży i tworzenie go jest na pewno kosztowniejsze niż np. stworzenie obiektu lekkiej klasy (np. anonimowej, włączając w to lambdy) implementującej Runnable, ale nie rozszerzającej Thread.

0

@Wibowit: Jeśli dodam do klasy interfejs Runnable to i tak muszę później stworzyć obiekt Thread żeby uruchomić aplikacje w wątku !
Bez tytułu.png

0
plugan300 napisał(a):

@Wibowit: Jeśli dodam do klasy interfejs Runnable to i tak muszę później stworzyć obiekt Thread żeby uruchomić aplikacje w wątku !

Zgadza się, ale wcześniej napisałeś, że chcesz odpalić metodę Thread.run(), a nie Thread.start(). Chcesz w końcu odpalić kod w osobnym wątku czy nie? Po co odpalasz Thread.run()?

0

@Wibowit: A jeśli mam zadeklarowane pole w klasie "B", przyjmijmy że Klasy "A" którą sam sobie stworzyłem i w metodzie klasy "B" cały czas inicjalizuję obiekt tej klasy "a = new A();" to nie będzie spowalniać aplikacji, czy te obiekty istnieją czy są nadpisywane?

0

@plugan300: Zrobiłem szybko coś takiego, lewym klawiszem myszki uruchamiam wątek, a prawym zatrzymuję. Jest to poprawne czy programy będą przez to wolniejsze ?
screenshot-20210903142236.png

4

"a = new A();"

To zawsze tworzy nowy obiekt. Im cięższy ten obiekt, tym więcej to kosztuje. Jeżeli pod a była referencja do starego obiektu, to stary obiekt będzie istniał dopóki GC się nim nie zajmie. Jeżeli stary obiekt to uruchomiony wątek, to GC go nie sprzątnie dopóki ten wątek się nie zakończy.

czy te obiekty istnieją czy są nadpisywane

Nadpisywanie obiektów w Javie? W Javie możesz zmienić pole w obiekcie, ale całości obiektu naraz nie nadpiszesz.

będzie spowalniać aplikacji

Im więcej generujesz śmieci, tym więcej GC ma roboty. Obiekt typu Thread jest cięższy niż obiekt typu Runnable. Im więcej uruchomionych wątków, tym większe ryzyko, że zabraknie zasobów.

Ze zrzutów ekranu domyślam się, że chodzi o jakieś cykliczne akcje do wykonania. Do tego możesz użyć https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html (utworzyć to za pomocą https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html ) i metod schedule..., które zwracają obiekty typu https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledFuture.html i mają metodę cancel. Taki obiekt typu ScheduledFuture jest lekki, w porównaniu do obiektu typu Thread, więc posługując się ScheduledFuture program powinien być przynajmniej ciutkę lżejszy i szybszy (zależy ile tych wątków teraz tworzysz).

0

Thread w javie może być odpalony tylko raz. Możliwości obejścia tego są różne - możesz mieć np. pulę wątków wykonujących jakieś zadania, pobierających to co mają zrobić z jakiegoś wspólnego miejsca. Wątek, jak każdy inny obiekt jest sprzątany przez GC. Przed tym sprzątnięciem chronią go 2 rzeczy:

  • Zewnętrzna referencja, czyli przypisanie obiektu wątku do jakiejś zmiennej.
  • To, że jest aktywny (czyli wciąż wykonuje się to co masz w metodzie run(). Aktywne wątki w Javie robią za Garbage Collector root.

Dopiero jak oba powyższe warunki są spełnione, do akcji ma szansę wkroczyć GC i w sobie znanym momencie (już teraz, albo nigdy) uprzątnąć pozostałości ze sterty.

Wychodząc poza temat - jeżeli piszesz to produkcyjnie, to warto się zapoznać ze współczesnymi podejściami. W większości prostych wypadków w zupełności starcza coś na zasadzie:

List<Task> tasks = .....;
List<Result> results = tasks.parallelStream().map(t -> t.doWhateverYouNeedAndReturnnResult()).collect(Collectors.toList());

W bardziej wypasionych przypadkach warto popatrzeć np. na Future.

1 użytkowników online, w tym zalogowanych: 0, gości: 1