Od czasu, który spędziłem z wątkami w Javie, znalazłem dwa sposoby pisania wątków:
Z implements Runnable
:
public class MyRunnable implements Runnable {
public void run() {
//Code
}
}
//Started with a "new Thread(new MyRunnable()).start()" call
Lub z extends Thread
:
public class MyThread extends Thread {
public MyThread() {
super("MyThread");
}
public void run() {
//Code
}
}
//Started with a "new MyThread().start()" call
Czy jest jakaś znacząca różnica w tych dwóch blokach kodu?
java
multithreading
runnable
implements
java-threads
użytkownik65374
źródło
źródło
interrupt()
. Znowu jest to pomysł, może być przydatny w odpowiednim przypadku, jednak nie polecam go.Odpowiedzi:
Tak: narzędzia
Runnable
to preferowany sposób, IMO. Tak naprawdę nie specjalizujesz się w zachowaniu wątku. Po prostu dajesz temu coś do uruchomienia. Oznacza to, że kompozycja jest filozoficznie „czystszą” drogą.W praktyce oznacza to, że możesz implementować
Runnable
i rozszerzać także z innej klasy.źródło
if (numberCores > 4) myExecutor.excute(myRunnable); else myRunnable.run()
extends Thread
, a jeśli nie chcesz gwintowania dlaczego byś nawet wdrożyćRunnable
...tl; dr: implementuje Runnable jest lepszy. Zastrzeżenie jest jednak ważne
Ogólnie rzecz biorąc, zalecałbym
Runnable
raczej użycie czegoś takiego , niżThread
ponieważ pozwala to na luźne powiązanie pracy z wyborem współbieżności. Na przykład, jeśli użyjesz aRunnable
i zdecydujesz później, że tak naprawdę nie wymaga on własnegoThread
, możesz po prostu wywołać threadA.run ().Uwaga: W tym miejscu zdecydowanie odradzam stosowanie surowych nici. Wolę używać Callables i FutureTasks (z javadoc: „Obliczanie asynchroniczne z możliwością anulowania”). Integracja limitów czasu, prawidłowe anulowanie i pula wątków współczesnej obsługi współbieżności są dla mnie znacznie bardziej przydatne niż stosy surowych wątków.
Kontynuacja: istnieje
FutureTask
konstruktor, który pozwala korzystać z Runnables (jeśli jest to najbardziej wygodne) i nadal korzystać z nowoczesnych narzędzi do współbieżności. Aby zacytować javadoc :Jeśli nie potrzebujesz konkretnego wyniku, rozważ użycie konstrukcji formularza:
Jeśli więc zastąpimy je
runnable
TwoimthreadA
, otrzymamy:Inną opcją, która pozwala pozostać bliżej Runnables, jest ThreadPoolExecutor . Możesz użyć metody execute , aby przekazać Runnable do wykonania „danego zadania w przyszłości”.
Jeśli chcesz spróbować użyć puli wątków, powyższy fragment kodu stałby się podobny do następującego (przy użyciu metody fabrycznej Executors.newCachedThreadPool () ):
źródło
es
byłoby lepsze jako pole statyczne (lub wstrzykiwane), więc jest tworzone tylko raz.FutureTask
ogół nie jest tym, co chcesz robić.ExecutorService
s stworzy odpowiedniFuture
dla ciebie, gdy / im. Podobnie dla s i kiedy a / .submit
Runnable
Callable
ScheduledExecutorService
ScheduledFuture
schedule
Runnable
Callable
Morał historii:
Dziedzicz tylko, jeśli chcesz zastąpić niektóre zachowania.
A raczej należy to rozumieć jako:
Dziedzicz mniej, interfejs więcej.
źródło
run()
metody.java.lang.Thread
poprzez przesłonięcierun()
metody. W takim przypadku musisz zastąpićstart()
metodę. Zwykle po prostu ponownie wykorzystujesz zachowaniejava.lang.Thread
poprzez wstrzyknięcie bloku wykonawczego dorun()
metody.Cóż, tyle dobrych odpowiedzi, chcę dodać więcej na ten temat. Pomoże to zrozumieć
Extending v/s Implementing Thread
.Rozszerza bardzo ściśle wiąże dwa pliki klas i może sprawić, że niektóre z nich będą bardzo trudne w obsłudze kodu.
Oba podejścia wykonują tę samą pracę, ale były pewne różnice.
Najczęstszą różnicą jest
Jednak jedną znaczącą różnicą między implementacją Runnable a rozszerzaniem Thread jest to
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.
Poniższy przykład pomoże ci lepiej zrozumieć
Wyjście powyższego programu.
W podejściu opartym na interfejsie Runnable tworzona jest tylko jedna instancja klasy i została ona współużytkowana przez różne wątki. Tak więc wartość licznika jest zwiększana dla każdego dostępu do wątku.
Natomiast w podejściu do klasy wątków musisz utworzyć osobną instancję dla każdego dostępu do wątku. W związku z tym dla każdej instancji klasy przydzielana jest inna pamięć, a każda ma osobny licznik, wartość pozostaje taka sama, co oznacza, że nie nastąpi przyrost, ponieważ żadne odwołanie do obiektu nie jest takie samo.
Kiedy używać Runnable?
Użyj interfejsu Runnable, jeśli chcesz uzyskać dostęp do tych samych zasobów z grupy wątków. Unikaj tutaj używania klasy wątków, ponieważ tworzenie wielu obiektów zużywa więcej pamięci i staje się to dużym obciążeniem wydajnościowym.
Klasa implementująca Runnable nie jest wątkiem, a jedynie klasą. Aby Runnable mógł zostać Wątkiem, musisz utworzyć instancję Wątka i przekazać się jako cel.
W większości przypadków interfejs Runnable powinien być używany, jeśli planujesz zastąpić
run()
metodę, a nie inne metody wątku. Jest to ważne, ponieważ klasy nie powinny być podklasowane, chyba że programista zamierza zmodyfikować lub poprawić podstawowe zachowanie klasy.Gdy zachodzi potrzeba rozszerzenia nadklasy, implementacja interfejsu Runnable jest bardziej odpowiednia niż użycie klasy Thread. Ponieważ możemy rozszerzyć kolejną klasę podczas implementacji interfejsu Runnable, aby utworzyć wątek.
Mam nadzieję, że to pomoże!
źródło
ExtendsThread et = new ExtendsThread();
Thread tc1 = new Thread(et);
tc1.start();
Thread.sleep(1000);
Thread tc2 = new Thread(et);
tc2.start();
Thread.sleep(1000);
Thread tc3 = new Thread(et);
tc3.start();
czy jest bardziej przejrzysta?Thread
funkcję inkrementacji, czy to stwierdzenie jestby extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance
błędne? Jeśli nie, to co to pokazuje?Jedną z rzeczy, które mnie zaskakują, nie wspomniano jeszcze, że implementacja
Runnable
czyni twoją klasę bardziej elastyczną.Jeśli rozszerzysz wątek, czynność, którą wykonujesz, zawsze będzie w wątku. Jeśli jednak wdrożysz,
Runnable
nie musi tak być. Możesz uruchomić go w wątku lub przekazać go do jakiejś usługi modułu wykonującego, lub po prostu przekazać jako zadanie w ramach jednej aplikacji wątkowej (może być uruchomione później, ale w tym samym wątku). Opcje są o wiele bardziej otwarte, jeśli po prostu użyjesz,Runnable
niż jeśli będziesz się z nimi wiązaćThread
.źródło
Thread
przedmiotem, ponieważThread implements Runnable
… ;-) Ale „czuje się lepiej”, robiąc te rzeczy za pomocąRunnable
niż za pomocąThread
!Thread
dodaje wiele dodatkowych rzeczy, których nie potrzebujesz, aw wielu przypadkach nie chcesz. Zawsze lepiej jest wdrożyć interfejs, który pasuje do tego, co faktycznie robisz.Jeśli chcesz zaimplementować lub rozszerzyć dowolną inną klasę,
Runnable
interfejs jest najbardziej preferowany, w przeciwnym razie, jeśli nie chcesz, aby żadna inna klasa rozszerzała lub implementowała,Thread
preferowana jest klasa.Najczęstszą różnicą jest
Podczas
extends Thread
zajęć nie możesz już przedłużyć żadnej innej wymaganej klasy. (Jak wiadomo, Java nie pozwala na dziedziczenie więcej niż jednej klasy).Kiedy możesz
implements Runnable
, możesz zaoszczędzić miejsce na zajęciach, aby przedłużyć dowolną inną klasę w przyszłości lub teraz.Java nie obsługuje wielu dziedziczeń, co oznacza, że możesz rozszerzyć tylko jedną klasę w Javie, więc po rozszerzeniu klasy wątku straciłeś szansę i nie możesz rozszerzyć ani odziedziczyć innej klasy w Javie.
W programowaniu obiektowym rozszerzenie klasy zazwyczaj oznacza dodanie nowej funkcjonalności oraz modyfikację lub poprawę zachowań. Jeśli nie wprowadzamy żadnych modyfikacji w wątku, użyj zamiast tego interfejsu Runnable.
Interfejs uruchamialny reprezentuje zadanie, które można wykonać za pomocą zwykłego wątku lub executorów lub w inny sposób. więc logiczne rozdzielenie Zadania jako Runnable niż Thread jest dobrą decyzją projektową.
Oddzielenie zadania jako Wykonalnego oznacza, że możemy ponownie użyć zadania, a także ma swobodę wykonywania go z różnych środków. ponieważ nie można ponownie uruchomić wątku po jego zakończeniu. ponownie Runnable vs Thread dla zadania, Runnable jest zwycięzcą.
Projektant Java rozpoznaje to i dlatego Executors akceptują Runnable jako Task i mają wątek roboczy, który wykonuje to zadanie.
Dziedziczenie wszystkich metod wątków jest dodatkowym obciążeniem tylko dla przedstawienia zadania, które można łatwo wykonać za pomocą Runnable.
Dzięki uprzejmości javarevisited.blogspot.com
Były to niektóre z istotnych różnic między Threadem a Runnable w Javie. Jeśli znasz jakieś inne różnice między Wątkiem a Runnable, udostępnij je za pomocą komentarzy. Ja osobiście używam Runnable zamiast Thread w tym scenariuszu i zaleca używanie interfejsu Runnable lub Callable na podstawie twoich wymagań.
Jednak istotną różnicą jest.
Podczas
extends Thread
zajęć każdy wątek tworzy unikalny obiekt i łączy się z nim. Kiedy Tyimplements Runnable
dzieli ten sam obiekt z wieloma wątkami.źródło
Właściwie, to nie jest mądre, aby porównać
Runnable
iThread
ze sobą nawzajem.Te dwa mają zależność i związek w wielowątkowości, podobnie jak
Wheel and Engine
związek z pojazdem silnikowym.Powiedziałbym, że jest tylko jeden sposób na wielowątkowość z dwoma krokami. Pozwól mi powiedzieć.
Runnable:
Podczas implementacji
interface Runnable
oznacza to, że tworzysz coś, co znajduje sięrun able
w innym wątku. Teraz tworzenie czegoś, co może działać w wątku (uruchamialne w wątku), nie oznacza tworzenia wątku.Klasa
MyRunnable
jest więc zwykłą klasą zvoid run
metodą. I to będą obiekty zwykłe z tylko metodą,run
która zadziała normalnie po wywołaniu. (chyba że przekażemy obiekt w wątku).Wątek:
class Thread
powiedziałbym, że jest to bardzo specjalna klasa z możliwością uruchomienia nowego wątku, który faktycznie umożliwia wielowątkowość za pomocą tejstart()
metody.Dlaczego nie warto porównywać?
Ponieważ potrzebujemy ich obu do wielowątkowości.
Do wielowątkowości potrzebujemy dwóch rzeczy:
Tak więc technicznie i teoretycznie oba z nich są konieczne, aby rozpocząć wątek, jeden będzie działać, a drugi sprawi, że zacznie działać (jak
Wheel and Engine
w przypadku pojazdu silnikowego).Dlatego nie możesz rozpocząć wątku
MyRunnable
, musisz przekazać go do instancjiThread
.Ale możliwe jest, aby utworzyć i uruchomić wątku tylko przy użyciu
class Thread
ponieważ klasaThread
implementujeRunnable
tak wszyscy wiemy,Thread
także jestRunnable
w środku.Wreszcie
Thread
iRunnable
uzupełniają się nawzajem w przypadku wielowątkowości, a nie konkurencji lub wymiany.źródło
ThreadA
nie ma już sensuPowinieneś zaimplementować Runnable, ale jeśli pracujesz na Javie 5 lub wyższej, nie powinieneś go uruchamiać,
new Thread
ale zamiast tego użyj ExecutorService . Aby uzyskać szczegółowe informacje, zobacz: Jak wdrożyć proste wątkowanie w Javie .źródło
Nie jestem ekspertem, ale mogę wymyślić jeden powód, aby zaimplementować Runnable zamiast rozszerzyć Wątek: Java obsługuje tylko pojedyncze dziedziczenie, więc możesz rozszerzyć tylko jedną klasę.
Edycja: pierwotnie było powiedziane: „Implementacja interfejsu wymaga mniej zasobów”. ale musisz utworzyć nową instancję wątku tak czy inaczej, więc było to źle.
źródło
Powiedziałbym, że istnieje trzeci sposób:
Być może trochę na to wpływa moje ostatnie użycie JavaScript i ActionScript 3, ale w ten sposób twoja klasa nie musi implementować dość niejasnego interfejsu
Runnable
.źródło
Wraz z wydaniem Java 8 istnieje teraz trzecia opcja.
Runnable
jest interfejsem funkcjonalnym , co oznacza, że jego instancje można tworzyć za pomocą wyrażeń lambda lub odwołań do metod.Twój przykład można zastąpić:
lub jeśli chcesz użyć
ExecutorService
odwołania do metody i:To nie są tylko znacznie krótszy niż swoich przykładach, ale również pochodzić z wielu zalet wskazanych w innych odpowiedzi korzystania
Runnable
nadThread
, jak i za pomocą pojedynczego odpowiedzialności kompozycję, ponieważ nie jesteś specjalizujący zachowanie wątku. W ten sposób unika się również tworzenia dodatkowej klasy, jeśli wszystko czego potrzebujesz to takRunnable
jak w przykładach.źródło
() -> {}
ma reprezentować niestandardową logikę, której ktoś potrzebuje? Więc lepiej byłoby powiedzieć jako() -> { /* Code here */ }
?Tworzenie instancji interfejsu zapewnia czystszą separację między kodem a implementacją wątków, dlatego w tym przypadku wolałbym implementować Runnable.
źródło
Wydaje się, że wszyscy tutaj myślą, że wdrożenie Runnable jest właściwą drogą i tak naprawdę nie zgadzam się z nimi, ale moim zdaniem istnieje również możliwość rozszerzenia Thread, w rzeczywistości wykazaliście to w swoim kodzie.
Jeśli implementujesz Runnable, klasa, która implementuje Runnable, nie ma kontroli nad nazwą wątku, to kod wywołujący może ustawić nazwę wątku, tak jak:
ale jeśli rozszerzysz wątek, możesz zarządzać tym w samej klasie (tak jak w twoim przykładzie nazywasz wątek „ThreadB”). W takim przypadku:
A) może nadać mu bardziej przydatną nazwę do celów debugowania
B) wymuszają używanie tej nazwy we wszystkich instancjach tej klasy (chyba że zignorujesz fakt, że jest to wątek i zrobisz to z nim tak, jakby to był Runnable, ale mówimy tutaj o konwencji, więc w każdym razie zignoruj tę możliwość, którą czuję).
Możesz nawet na przykład pobrać ślad stosu jego utworzenia i użyć go jako nazwy wątku. Może się to wydawać dziwne, ale w zależności od struktury kodu może być bardzo przydatne do celów debugowania.
Może się to wydawać małą rzeczą, ale w przypadku bardzo złożonej aplikacji z dużą liczbą wątków i nagle wszystko „zatrzymało się” (albo z powodu impasu, albo być może z powodu wady protokołu sieciowego, który byłby mniejszy oczywiste - lub z innych niekończących się powodów), a następnie zrzut zrzutu stosu z Javy, gdzie wszystkie wątki są nazywane „Thread-1”, „Thread-2”, „Thread-3” nie zawsze jest bardzo użyteczny (zależy to od tego, jakie są twoje wątki ustrukturyzowane i czy można pożytecznie stwierdzić, który jest po prostu przez ich ślad stosu - nie zawsze jest to możliwe, jeśli używasz grup wielu wątków, wszystkie z tym samym kodem).
Powiedziawszy, że możesz oczywiście zrobić powyższe w sposób ogólny, tworząc rozszerzenie klasy wątku, która ustawia swoją nazwę na ślad stosu wywołania jej utworzenia, a następnie użyj tego z implementacjami Runnable zamiast standardowej klasy wątku java (patrz poniżej), ale oprócz śledzenia stosu może być więcej informacji specyficznych dla kontekstu, które byłyby przydatne w nazwie wątku do debugowania (odwołanie do jednej z wielu kolejek lub gniazd, które mógłby przetwarzać, na przykład, w którym to przypadku wolisz rozszerz Wątek specjalnie dla tego przypadku, aby kompilator zmusił Ciebie (lub inne osoby korzystające z twoich bibliotek) do przekazania pewnych informacji (np. kolejki / gniazda) do użycia w nazwie).
Oto przykład ogólnego wątku ze śladami stosu wywołującego jako jego nazwą:
a oto próbka wyników porównująca dwie nazwy:
źródło
Runnable
może rzeczywiście kontrolować nazwę wątku, ponieważ wątek uruchamiający kod jest z definicji bieżącym wątkiem (a każdy kod, który przechodzi testy bezpieczeństwa, ma kontrolę nad nazwami wątków). Biorąc pod uwagę, że poświęcisz połowę swojego postu na „omg, a co z nazwami wątków!”, Wydaje się to dość poważna sprawa.Można uruchomić, ponieważ:
Nawet jeśli nie potrzebujesz tego teraz, możesz w przyszłości. Ponieważ zastąpienie wątku nie przynosi korzyści, Runnable jest lepszym rozwiązaniem.
źródło
Ponieważ jest to bardzo popularny temat, a dobre odpowiedzi są szeroko rozpowszechnione i omawiane z wielką głębią, uznałem, że uzasadnione jest skompilowanie dobrych odpowiedzi od innych w bardziej zwięzłej formie, dzięki czemu nowi użytkownicy mają z góry łatwy przegląd:
Zazwyczaj rozszerzasz klasę, aby dodać lub zmodyfikować funkcjonalność. Tak więc, jeśli nie chcesz , aby zastąpić dowolny zachowanie wątku , a następnie użyć Runnable.
W tym samym świetle, jeśli nie trzeba do dziedziczą metod wątku, można to zrobić bez tego narzutu przy użyciu Runnable.
Pojedyncze dziedziczenie : Jeśli rozszerzysz wątek, nie możesz rozszerzyć go z żadnej innej klasy, więc jeśli to jest to, co musisz zrobić, musisz użyć Runnable.
Jest to dobry projekt odrębnej logiki domeny z środków technicznych, w tym sensie, że lepiej jest mieć Runnable zadanie izolować swoje zadanie ze swojej biegacza .
Możesz wykonać ten sam obiekt Runnable wiele razy , jednak obiekt Thread można uruchomić tylko raz. (Być może powód, dla którego Wykonawcy akceptują Runnable, ale nie wątki.)
Jeśli rozwiniesz swoje zadanie jako Runnable, masz pełną elastyczność, jak korzystać z niego teraz iw przyszłości . Możesz uruchomić go jednocześnie przez Executory, ale także przez Thread. I nadal możesz używać / wywoływać go nie jednocześnie w tym samym wątku, tak jak każdy inny zwykły typ / obiekt.
To sprawia, że łatwiejsze do odrębnych zadań-logicznych i współbieżności aspektów w swoich testów jednostkowych .
Jeśli jesteś zainteresowany tym pytaniem, możesz być również zainteresowany różnicą między wywoływalnymi a uruchamialnymi .
źródło
Różnica między rozszerzaniem wątku a implementacją Runnable to:
źródło
Jest to omówione w samouczku Definiowanie i rozpoczynanie wątku Oracle :
Innymi słowy, implementacja
Runnable
będzie działać w scenariuszach, w których klasa rozszerza klasę inną niżThread
. Java nie obsługuje wielokrotnego dziedziczenia. RozszerzanieThread
nie będzie również możliwe w przypadku korzystania z niektórych interfejsów API zarządzania wątkami wysokiego poziomu. Jedynym scenariuszem, w którymThread
preferowane jest rozszerzenie, jest mała aplikacja, która nie będzie podlegać aktualizacjom w przyszłości. Prawie zawsze lepiej jest go wdrożyć,Runnable
ponieważ jest on bardziej elastyczny w miarę rozwoju projektu. Zmiana projektu nie będzie miała większego wpływu, ponieważ można zaimplementować wiele interfejsów w Javie, ale rozszerzyć tylko jedną klasę.źródło
Najprostszym wyjaśnieniem byłoby zaimplementowanie,
Runnable
że możemy przypisać ten sam obiekt do wielu wątków i każdyThread
ma te same stany i zachowanie tego samego obiektu.Załóżmy na przykład, że istnieją dwa wątki, wątek 1 umieszcza liczbę całkowitą w tablicy, a wątek 2 pobiera liczby całkowite z tablicy, gdy tablica jest zapełniona. Zauważ, że aby wątek działał, musi znać stan tablicy, niezależnie od tego, czy wątek ją zapełnił, czy nie.
Implementacja
Runnable
pozwala na elastyczność w udostępnianiu obiektu, a jednocześnieextends Thread
umożliwia tworzenie nowych obiektów dla każdego wątku, dlatego każda aktualizacja wykonywana przez wątek 1 zostaje utracona w wątku 2.źródło
Jeśli się nie mylę, jest to mniej więcej podobne
Jaka jest różnica między interfejsem a klasą abstrakcyjną?
przedłuża ustanawia relację „ Jest A ”, a interfejs zapewnia możliwość „ Ma ”.
Wolę implementuje Runnable :
Wolę „ przedłuża wątek ”:
Zasadniczo nie trzeba zastępować zachowania wątku. Więc implementuje Runnable jest preferowany przez większość czasu.
Z drugiej strony korzystanie z zaawansowanych
ExecutorService
lubThreadPoolExecutorService
API zapewnia większą elastyczność i kontrolę.Spójrz na to pytanie SE:
ExecutorService vs Casual Thread Spawner
źródło
Oddzielenie klasy Thread od implementacji Runnable pozwala również uniknąć potencjalnych problemów z synchronizacją między wątkiem a metodą run (). Oddzielny Runnable ogólnie daje większą elastyczność w sposobie odwoływania się i wykonywania kodu wykonalnego.
źródło
To S od SOLID : Single odpowiedzialność.
Gwint ucieleśnia działa kontekst (jak w kontekście wykonania: stos oraz identyfikator wątku, etc.) do asynchronicznego wykonania kawałka kodu. Idealnie ten fragment kodu powinien być tą samą implementacją, zarówno synchroniczną, jak i asynchroniczną .
Jeśli połączysz je w jedną implementację, wynikowy obiekt daje dwie niezwiązane przyczyny zmian:
Jeśli używany język obsługuje klasy częściowe lub wielokrotne dziedziczenie, możesz posegregować każdą przyczynę w jej własnej superklasie, ale sprowadza się to do złożenia dwóch obiektów, ponieważ ich zestawy funkcji nie pokrywają się. To dotyczy teorii.
W praktyce, ogólnie rzecz biorąc, program nie musi być bardziej złożony niż to konieczne. Jeśli masz jeden wątek pracujący nad konkretnym zadaniem, bez zmiany tego zadania, prawdopodobnie nie ma sensu tworzyć oddzielnych klas zadań, a kod jest prostszy.
W kontekście Javy , ponieważ narzędzie już tam jest, prawdopodobnie łatwiej jest rozpocząć bezpośrednio od samodzielnych
Runnable
klas i przekazać ich instancje doThread
(lubExecutor
) instancji. Raz przyzwyczajony do tego wzorca, nie jest trudniejszy w użyciu (a nawet czytaniu) niż prosty przypadek wątku.źródło
Jednym z powodów, dla których chcesz wdrożyć interfejs zamiast rozszerzać klasę podstawową jest to, że już rozszerzasz inną klasę. Możesz rozszerzyć tylko jedną klasę, ale możesz zaimplementować dowolną liczbę interfejsów.
Jeśli rozszerzysz Wątek, zasadniczo uniemożliwiasz wykonanie swojej logiki przez inny wątek niż „ten”. Jeśli chcesz, aby jakiś wątek wykonywał twoją logikę, lepiej po prostu zaimplementować Runnable.
źródło
jeśli użyjesz Runnable, możesz zaoszczędzić miejsce, aby rozszerzyć się na dowolną inną klasę.
źródło
Czy możemy ponownie odwiedzić podstawowy powód, dla którego chcieliśmy, aby nasza klasa zachowywała się jak
Thread
? Nie ma żadnego powodu, chcieliśmy po prostu wykonać zadanie, najprawdopodobniej w trybie asynchronicznym, co dokładnie oznacza, że wykonanie zadania musi rozgałęzić się z naszego głównego wątku i głównego wątku, jeśli zakończy się wcześnie, może, ale nie musi, czekać dla rozgałęzionej ścieżki (zadanie).Jeśli to jest cały cel, to gdzie widzę potrzebę specjalistycznego wątku. Można tego dokonać, pobierając wątek RAW z puli wątków systemu i przypisując mu nasze zadanie (może być instancją naszej klasy) i to wszystko.
Przestrzegajmy więc koncepcji OOP i napisz klasę, której potrzebujemy. Istnieje wiele sposobów robienia rzeczy, ważne jest robienie tego we właściwy sposób.
Potrzebujemy zadania, więc napisz definicję zadania, którą można uruchomić w wątku. Więc użyj Runnable.
Zawsze pamiętaj,
implements
jest specjalnie używany do nadawania zachowania iextends
służy do nadawania cechy / właściwości.Nie chcemy własności wątku, zamiast tego chcemy, aby nasza klasa zachowywała się jako zadanie, które można uruchomić.
źródło
Tak, jeśli wywołasz wywołanie ThreadA, nie musisz wywoływać metody start, a metoda run jest wywołaniem po wywołaniu tylko klasy ThreadA. Ale jeśli używasz wywołania ThreadB, musisz koniecznie uruchomić wątek początkowy dla metody uruchamiania wywołania. Jeśli masz dodatkową pomoc, odpowiedz mi.
źródło
Uważam, że najbardziej użyteczne jest użycie Runnable z wszystkich wymienionych powodów, ale czasami lubię rozszerzać Thread, aby móc stworzyć własną metodę zatrzymywania wątków i wywołać ją bezpośrednio w utworzonym wątku.
źródło
Java nie obsługuje wielokrotnego dziedziczenia, więc jeśli rozszerzysz klasę Thread, żadna inna klasa nie zostanie przedłużona.
Na przykład: jeśli tworzysz aplet, musi on rozszerzyć klasę apletu, więc tutaj jedynym sposobem na utworzenie wątku jest implementacja interfejsu Runnable
źródło
Runnable
to interfejs, natomiastThread
klasa, która implementuje ten interfejs. Z punktu widzenia projektowania powinna istnieć wyraźna separacja między sposobem definiowania zadania a sposobem jego wykonywania. Pierwszy z nich jest odpowiedzialny zaRunnalbe
wdrożenie, a drugi to zadanieThread
klasy. W większości przypadków wdrożenieRunnable
jest właściwym sposobem postępowania.źródło
Różnica między Threadem a Runnable. Jeśli tworzymy Thread za pomocą klasy Thread, to liczba wątków jest równa liczbie utworzonych przez nas obiektów. Jeśli tworzymy wątek za pomocą implementowalnego interfejsu, możemy użyć jednego obiektu do utworzenia wielu wątków, więc jeden obiekt jest współdzielony przez wiele wątków, więc zajmie mniej pamięci
Zatem w zależności od wymagań, jeśli nasze dane nie są wrażliwe. Więc może być dzielony między wiele wątków, których możemy użyć interfejsu Runnable.
źródło
Dodając tutaj moje dwa centy - Zawsze, gdy to możliwe, użyj
implements Runnable
. Poniżej znajdują się dwa zastrzeżenia, dlaczego nie należy używaćextends Thread
sIdealnie nie powinieneś nigdy rozszerzać klasy Thread;
Thread
klasa powinna być wykonanafinal
. Przynajmniej takie metody jakthread.getId()
. Zobacz tę dyskusję, aby znaleźć błąd związany z rozszerzaniemThread
s.Ci, którzy lubią rozwiązywać łamigłówki, mogą zobaczyć kolejny efekt uboczny rozszerzenia wątku. Poniższy kod wyświetli kod nieosiągalny, gdy nikt ich nie powiadomi.
Proszę zobaczyć http://pastebin.com/BjKNNs2G .
źródło