"implements Runnable" vs "extends Thread" w Javie

Z tego, co 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 ?

Author: Steve Chambers, 2009-02-12

30 answers

Tak: implementuje Runnable jest preferowanym sposobem, IMO. Nie specjalizujesz się w zachowaniu wątku. Po prostu dajesz mu coś do biegania. Oznacza to, że kompozycja jest filozoficznie "czystszą" drogą.

W językupraktycznym oznacza to, że możesz zaimplementować Runnable i rozszerzyć z innej klasy.

 1466
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-22 22:09:24

Tl; dr: implements Runnable jest lepszy. Jednak zastrzeżenie jest ważne

Ogólnie polecam użycie czegoś takiego jak Runnable zamiast Thread, ponieważ pozwala to zachować pracę tylko luźno połączoną z wyborem współbieżności. Na przykład, jeśli użyjesz Runnable i później zdecydujesz, że to nie wymaga własnej Thread, możesz po prostu wywołać threadA.run ().

Zastrzeżenie: tutaj zdecydowanie odradzam stosowanie surowych Nici. Zdecydowanie wolę używać Callables i FutureTasks (z javadoc: "a cancellable asynchronous computation"). Integracja timeoutów, odpowiednie anulowanie i łączenie wątków z nowoczesną obsługą współbieżności są dla mnie znacznie bardziej przydatne niż stosy surowych wątków.

Kontynuacja: Istnieje FutureTask konstruktor, który pozwala na korzystanie z Runnables (jeśli to jest to, co jest najbardziej wygodne) i nadal uzyskać korzyści z nowoczesne narzędzia współbieżności. Cytuję javadoc:

Jeśli nie potrzebujesz konkretnego wyniku, rozważ użycie konstrukcji postaci:

Future<?> f = new FutureTask<Object>(runnable, null)

Więc, jeśli zamienimy ich runnable na twoje threadA, otrzymamy następujące:

new FutureTask<Object>(threadA, null)

Inną opcją, która pozwala Ci pozostać bliżej Runnables, jest ThreadPoolExecutor . Możesz użyć metody execute , aby przekazać w Runnable to execute "dane zadanie kiedyś w przyszłości."

Jeśli chcesz aby spróbować użyć puli wątków, powyższy fragment kodu stałby się czymś w rodzaju poniższego (używając Executorów.newCachedThreadPool () metoda fabryczna):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
 500
Author: Bob Cross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-28 07:26:50

Morał historii:

Dziedzicz tylko wtedy, gdy chcesz nadpisać pewne zachowanie.

A raczej powinno być czytane jako:

Dziedzicz mniej, interfejs więcej.

 232
Author: panzerschreck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-28 16:26:50

No tak wiele dobrych odpowiedzi, chcę dodać więcej na ten temat. Pomoże to zrozumieć Extending v/s Implementing Thread.
rozszerza bindy dwóch plików klas bardzo blisko i może spowodować dość trudne do czynienia z kodem.

Oba podejścia wykonują tę samą pracę, ale były pewne różnice.
najczęstszą różnicą jest

  1. kiedy rozszerzasz klasę Thread, potem nie możesz rozszerzyć żadnej innej klasy, której potrzebujesz. (Jak wiadomo, Java nie pozwala na dziedziczenie więcej niż jednego klasy).
  2. kiedy zaimplementujesz Runnable, możesz zaoszczędzić miejsce dla swojej klasy, aby rozszerzyć inną klasę w przyszłości lub teraz.

jednak jedna znacząca różnica między implementacją Runnable a rozszerzaniem wątku jest taka, że
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 pomaga lepiej zrozumieć

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

Wyjście powyższego programu.

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

W podejściu Runnable interface, tylko jedna instancja klasa jest tworzona i jest współdzielona przez różne wątki. Tak więc wartość counter jest zwiększana dla każdego dostępu do wątku.

Podczas gdy, podejście klasy Thread, musisz utworzyć osobną instancję dla każdego dostępu do wątku. Dlatego dla każdej instancji klasy przydzielana jest inna pamięć i każda ma oddzielny licznik, wartość pozostaje taka sama, co oznacza, że nie dojdzie do przyrostu, ponieważ żadna z referencji do obiektu nie jest taka sama.

Kiedy używać / Align = "left" /
Użyj interfejsu Runnable, gdy chcesz uzyskać dostęp do tego samego zasobu z grupy wątków. Unikaj tutaj używania klasy Thread, ponieważ tworzenie wielu obiektów zużywa więcej pamięci i staje się dużym obciążeniem wydajności.

Klasa, która implementuje Runnable, nie jest wątkiem, a tylko klasą. Aby Runnable stał się wątkiem, musisz utworzyć instancję wątku i przekazać się jako cel.

W większości przypadków należy używać interfejsu Runnable jeśli planujesz tylko nadpisać metodę run(), a nie Inne metody wątku. Jest to ważne, ponieważ klasy nie powinny być podklasowane, chyba że programista zamierza zmodyfikować lub ulepszyć podstawowe zachowanie klasy.

Gdy istnieje potrzeba rozszerzenia klasy superclass, implementacja interfejsu Runnable jest bardziej odpowiednia niż użycie klasy Thread. Ponieważ możemy rozszerzyć inną klasę podczas implementacji interfejsu Runnable, aby utworzyć wątek.

Mam nadzieję, że to pomoże!

 189
Author: Rupesh Yadav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-11 10:47:33

Jedna rzecz, która mnie dziwi, to fakt, że implementacja Runnable sprawia, że twoja klasa jest bardziej elastyczna.

Jeśli rozszerzysz wątek, to akcja, którą wykonujesz, zawsze będzie w wątku. Jeśli jednak zaimplementujesz Runnable, nie musi tak być. Można go uruchomić w wątku lub przekazać do jakiejś usługi wykonywacza lub po prostu przekazać jako zadanie w ramach pojedynczej aplikacji z wątkiem (może być uruchomione w późniejszym czasie, ale w ramach tego samego wątku). Opcje są o wiele bardziej otwarte, jeśli używasz Runnable, niż Jeśli wiążesz się z Thread.

 73
Author: Herms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-12 12:53:26

Jeśli chcesz zaimplementować lub rozszerzyć jakąkolwiek inną klasę, To Runnable interfejs jest najbardziej pożądany inne mądre jeśli nie chcesz, aby jakakolwiek inna klasa rozszerzyła lub zaimplementowała to Thread klasa jest preferowana

Najczęstszą różnicą jest

Tutaj wpisz opis obrazka

Kiedy ty extends Thread klasy, po tym nie możesz rozszerzyć żadnej innej klasy, której potrzebujesz. (Jak wiadomo, Java nie pozwala na dziedziczenie więcej niż jednej klasy).

Kiedy ty implements Runnable, możesz zaoszczędzić miejsce dla swojej klasy aby rozszerzyć inne zajęcia w przyszłości lub teraz.

  • Java nie obsługuje dziedziczenia wielokrotnego, 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 dziedziczyć innej klasy w Javie.

  • W programowaniu obiektowym Rozszerzanie klasy zazwyczaj oznacza dodawanie nowych funkcjonalności, modyfikowanie lub ulepszanie zachowań. Jeśli nie dokonujemy żadnych modyfikacji w wątku to użyj Runnable interface zamiast tego.

  • Interfejs Runnable reprezentuje zadanie, które może być wykonane przez zwykły wątek lub Executors lub w jakikolwiek inny sposób. tak więc logiczne rozdzielenie zadania jako Runnable niż Thread jest dobrą decyzją projektową.

  • Oddzielenie zadania jako Runnable 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ą.

  • Java projektant rozpoznaje to i dlatego wykonawcy akceptują Runnable jako zadanie i mają wątek roboczy, który wykonuje te zadanie.

  • Dziedziczenie wszystkich metod wątku jest dodatkowym obciążeniem tylko dla reprezentowania zadania, które można łatwo wykonać za pomocą Runnable.

Dzięki Uprzejmości z javarevisited.blogspot.com

Były to znaczące różnice między Thread i Runnable w Javie, jeśli znasz jakieś inne różnice na Thread vs Runnable niż Proszę podzielić się nim poprzez komentarze. Osobiście używam Runnable over Thread dla tego scenariusza i zaleca użycie interfejsu Runnable lub Callable w oparciu o twoje wymagania.

Jednak znacząca różnica jest.

Kiedy ty extends Thread klasa, każdy z Twoich wątków tworzy unikalny obiekt i kojarzy się z nim. Kiedy implements Runnable, dzieli ten sam obiekt z wieloma wątkami.

 66
Author: Nidhish Krishnan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-21 15:02:55

Właściwie, to nie jest mądre porównywać Runnable i Thread ze sobą.

Te dwa mają zależność i związek w wielowątkowości, podobnie jak Wheel and Engine związek pojazdu silnikowego.

Powiedziałbym, że istnieje tylko jeden sposób na wielowątkowość z dwoma krokami. Pozwól, że wyjaśnię.

Runnable:
Implementując interface Runnable oznacza to, że tworzysz coś, co jest run able w innym wątku. Teraz tworząc coś, co może działać wewnątrz thread (uruchamiany wewnątrz wątku), nie oznacza tworzenia wątku.
Tak więc klasa MyRunnable jest niczym innym jak zwykłą klasą z metodą void run. I to będą zwykłe obiekty z tylko metodą run, która będzie wykonywana normalnie po wywołaniu. (chyba że przekazujemy obiekt w wątku).

Wątek:
class Thread, powiedziałbym, że bardzo specjalna klasa z możliwością uruchamiania nowego wątku, która faktycznie umożliwia wielowątkowe przechodzenie przez jego start() metoda.

Dlaczego nie warto porównywać?
Ponieważ potrzebujemy ich obu do wielowątkowości.

Do wielowątkowości potrzebujemy dwóch rzeczy:

  • coś, co może działać wewnątrz wątku (Runnable).
  • coś, co może rozpocząć nowy wątek (Thread).

Więc technicznie i teoretycznie oba są niezbędne do uruchomienia wątku, jeden uruchomi , a drugi sprawi, że będzie działał (Jak Wheel and Engine z silnikiem pojazd).

Dlatego nie możesz rozpocząć wątku z MyRunnable musisz przekazać go do instancji Thread.

Ale możliwe jest tworzenie i uruchamianie wątku tylko przy użyciu class Thread, ponieważ klasa Thread implementuje Runnable, więc wszyscy wiemy, że Thread jest również Runnable wewnątrz.

W końcu Thread i Runnable uzupełniają się wzajemnie dla wielowątkowości, a nie konkurują lub zastępują.

 61
Author: Saif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 05:58:59

Powinieneś zaimplementować Runnable, ale jeśli używasz Javy 5 lub wyższej, nie powinieneś uruchamiać jej z new Thread, ale zamiast tego użyj ExecutorService. Po szczegóły patrz: jak zaimplementować prosty threading w Javie .

 41
Author: Fabian Steeg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36

Nie jestem ekspertem, ale mogę wymyślić jeden powód, aby zaimplementować Runnable zamiast extend Thread: Java obsługuje tylko pojedyncze dziedziczenie, więc można rozszerzyć tylko jedną klasę.

Edit: pierwotnie napisano: "implementacja interfejsu wymaga mniej zasobów."jak również, ale trzeba utworzyć nową instancję wątku tak czy inaczej, więc to było złe.

 31
Author: Powerlord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 14:32:01

Powiedziałbym, że jest trzecia droga:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

Może ma to wpływ na moje ostatnie intensywne użycie Javascript i Actionscript 3, ale w ten sposób twoja klasa nie musi implementować dość niejasnego interfejsu, takiego jak Runnable.

 19
Author: Bart van Heukelom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-25 21:41:00

Wraz z wydaniem Javy 8, istnieje teraz trzecia opcja.

Runnable jest funkcjonalnym interfejsem , co oznacza, że jego instancje mogą być tworzone za pomocą wyrażeń lambda lub odniesień do metod.

Twój przykład można zastąpić:

new Thread(() -> { /* Code here */ }).start()

Lub jeśli chcesz użyć ExecutorService i referencji metody:

executor.execute(runner::run)

Są one nie tylko znacznie krótsze niż twoje przykłady, ale także mają wiele zalet podanych w innych odpowiedziach dotyczących używania Runnable nad Thread, takie jak pojedyncza odpowiedzialność i używanie kompozycji, ponieważ nie specjalizujesz się w zachowaniu wątku. W ten sposób unika się również tworzenia dodatkowej klasy, jeśli wszystko, czego potrzebujesz, to Runnable, Jak to robisz w swoich przykładach.

 16
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-05 12:10:44

Tworzenie instancji interfejsu daje czystszą separację między kodem a implementacją wątków, więc wolałbym zaimplementować Runnable w tym przypadku.

 15
Author: starblue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 14:33:09
  1. Java nie obsługuje dziedziczenia wielokrotnego, co oznacza, że możesz rozszerzyć tylko jedną klasę w Javie, więc po rozszerzeniu Thread klasy straciłeś swoją szansę i nie możesz rozszerzyć ani dziedziczyć innej klasy w Javie.
  2. w programowaniu obiektowym Rozszerzanie klasy zazwyczaj oznacza dodawanie nowych funkcjonalności, modyfikowanie lub ulepszanie zachowań. Jeśli nie dokonujemy żadnych modyfikacji na Thread, to zamiast tego użyjemy interfejsu Runnable.
  3. Runnable interfejs reprezentuje Task, który może być wykonywane przez zwykły Thread lub Executors lub w jakikolwiek inny sposób. Więc logiczne rozdzielenie Task jako Runnable niż {[0] } jest dobrą decyzją projektową.
  4. oddzielenie zadania jako Runnable oznacza, że możemy ponownie użyć zadania, a także mamy swobodę wykonywania go z różnych środków. Ponieważ nie można ponownie uruchomić Thread po jego zakończeniu, ponownie Runnable vs Thread dla zadania, Runnable jest zwycięzcą.
  5. Java designer rozpoznaje to i dlatego Executors akceptuje Runnable jako Task i mają wątek roboczy, który wykonuje te zadanie.
  6. dziedziczenie wszystkich metod Thread jest dodatkowym obciążeniem tylko dla reprezentowania Task, co można łatwo zrobić za pomocą Runnable.
 12
Author: Hutashan Chandrakar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-21 15:45:57

Runnable ponieważ:

  • pozostawia większą elastyczność dla Runnable implementation to extend another class
  • oddziela Kod od wykonanie
  • pozwala na uruchomienie swojego runnable from a Thread Pool, the wątku zdarzenia, lub w jakikolwiek inny sposób w przyszłość.

Nawet jeśli nie potrzebujesz tego teraz, możesz w przyszłości. Ponieważ nie ma korzyści z nadrzędnego wątku, Runnable jest lepszym rozwiązaniem.

 10
Author: n13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-07 04:28:57

Wszyscy tutaj wydają się myśleć, że implementacja Runnable jest drogą do zrobienia i nie bardzo się z nimi nie Zgadzam, ale jest też powód do rozszerzenia wątku moim zdaniem, w rzeczywistości zademonstrowałeś to w swoim kodzie.

Jeśli zaimplementujesz Runnable, to klasa, która implementuje Runnable nie ma kontroli nad nazwą wątku, to kod wywołujący może ustawić nazwę wątku w następujący sposób:

new Thread(myRunnable,"WhateverNameiFeelLike");

Ale jeśli rozszerzysz wątek, będziesz mógł nim zarządzać w ramach klasy sam (tak jak w twoim przykładzie nazwiesz wątek 'ThreadB'). W tym przypadku ty:

A) może nadać jej bardziej użyteczną nazwę dla celów debugowania

B) wymuszają użycie tej nazwy dla wszystkich instancji tej klasy (chyba, że ignorujesz fakt, że jest to wątek i robisz z nim powyższe tak, jakby to był Runnable, ale mówimy tu o konwencji w każdym przypadku, więc możesz zignorować tę możliwość, którą czuję).

Możesz nawet na przykład wziąć ślad stosu jego utworzenia i użyj tego jako nazwy wątku. Może to wydawać się dziwne, ale w zależności od struktury kodu może być bardzo przydatne do celów debugowania.

To może wydawać się małą rzeczą, ale gdy masz bardzo złożoną aplikację z dużą ilością wątków i nagle rzeczy "przestały" (albo z powodu impasu, albo z powodu wady protokołu sieciowego, która byłaby mniej oczywista - lub z innych niekończących się powodów), otrzymujesz zrzut stosu z Javy, gdzie wszystkie wątki są usuwane. są nazywane 'Thread-1', 'Thread-2', 'Thread-3' nie zawsze są bardzo przydatne (zależy to od struktury twoich wątków i czy możesz z pożytkiem stwierdzić, który jest który po prostu po ich śladach stosu - nie zawsze jest to możliwe, jeśli używasz grup wielu wątków, wszystkie uruchomione ten sam kod).

Powiedziawszy, że możesz oczywiście zrobić powyższe w ogólny sposób, tworząc rozszerzenie klasy wątku, które ustawia jej nazwę na ślad stosu jego wywołania tworzenia, a następnie użyć go z zamiast standardowej klasy Java Thread (patrz poniżej), ale oprócz śledzenia stosu może być więcej informacji kontekstowych, które byłyby przydatne w nazwie wątku do debugowania (odniesienie do jednej z wielu kolejek lub gniazd, które może przetwarzać, na przykład w takim przypadku możesz preferować rozszerzenie wątku specjalnie dla tego przypadku, aby kompilator zmusił Cię (lub inne osoby korzystające z Twoich bibliotek) do przekazania pewnych informacji (np. Kolejka/Gniazdo). w pytaniu) do użycia w nazwie).

Oto przykład generycznego wątku z nazwą stosu wywołującego:

public class DebuggableThread extends Thread {
    private static String getStackTrace(String name) {
        Throwable t= new Throwable("DebuggableThread-"+name);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        t.printStackTrace(ps);
        return os.toString();
    }

    public DebuggableThread(String name) {
        super(getStackTrace(name));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new Thread());
        System.out.println(new DebuggableThread("MainTest"));
    }
}

A oto Przykładowe wyjście porównujące obie nazwy:

Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
    at DebuggableThread.getStackTrace(DebuggableThread.java:6)
    at DebuggableThread.<init>(DebuggableThread.java:14)
    at DebuggableThread.main(DebuggableThread.java:19)
,5,main]
 10
Author: AntonyM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-19 23:12:49

Ponieważ jest to bardzo popularny temat, a dobre odpowiedzi są szeroko rozpowszechnione i omawiane w dużej mierze, uznałem, że uzasadnione jest zestawianie dobrych odpowiedzi od innych w bardziej zwięzłą formę, więc nowicjusze mają łatwy przegląd z góry: {]}

  1. Zazwyczaj rozszerzasz klasę, aby dodać lub zmodyfikować funkcjonalność. Tak więc jeśli nie chcesz zastąpić dowolnymzachowaniem wątku , użyj Runnable.

  2. W tym samym świetle, jeśli nie potrzebujesz do inherit metody wątku, możesz to zrobić bez tego overhead używając Runnable.

  3. Single inheritance: 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.

  4. Dobrze jest oddzielić logikę domeny od środków technicznych, w tym sensie lepiej mieć Zadanie izolujące Twoje zadanie od Twoje runner .

  5. Możesz wykonać ten sam obiekt Runnable wiele razy, obiekt wątku można jednak uruchomić tylko raz. (Może powód, dla którego Executorzy akceptują Runnables, ale nie wątki.)

  6. Jeśli rozwijasz swoje zadanie jako Runnable, masz całą elastyczność, jak z niego korzystać teraz i w przyszłości. Możesz go uruchomić jednocześnie przez Executory, ale także przez wątek. I nadal możesz używać / nazywać go nie jednocześnie w tym samym wątku, tak jak każdy inny zwykły typ / obiekt.

  7. Ułatwia to również oddzielenie logiki zadań i współbieżności aspektów w Twoich testach jednostkowych .

  8. Jeśli jesteś zainteresowany tym pytaniem, możesz być również zainteresowany różnicą między Callable i Runnable .

 10
Author: Jörg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36

To jest omówione w Oracle ' S Definiowanie i uruchamianie wątku tutorial:

Którego z tych idiomów powinieneś użyć? Pierwszy idiom, który wykorzystuje Obiekt Runnable, jest bardziej ogólny, ponieważ obiekt Runnable może podklasa Klasa inna niż wątek. Drugi idiom jest łatwiejszy w użyciu w prostych aplikacjach, ale jest ograniczony faktem, że Twoje zadanie klasa musi być potomkiem wątku. Lekcja ta skupia się na pierwszym podejście, które oddziela Uruchamialne zadanie z obiektu Thread to wykonuje zadanie. Nie tylko jest to podejście bardziej elastyczne, ale ma ona zastosowanie do interfejsów API do zarządzania wątkami wysokiego poziomu objętych później.

Innymi słowy, implementacja Runnable będzie działać w scenariuszach, w których twoja klasa rozszerza klasę inną niż Thread. Java nie obsługuje dziedziczenia wielokrotnego. Ponadto rozszerzenie Thread nie będzie możliwe w przypadku korzystania z niektórych interfejsów API zarządzania wątkami wysokiego poziomu. Jedyny scenariusz, w którym Rozszerzenie Thread lepiej jest w małej aplikacji, która nie będzie podlegała aktualizacjom w przyszłości. Prawie zawsze lepiej jest wdrożyć Runnable, ponieważ jest 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ę.

 8
Author: Sionnach733,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 16:44:09

Jeśli się nie mylę, to jest mniej więcej podobne do

Jaka jest różnica między interfejsem a klasą abstrakcyjną?

Extends ustanawia " Is a " relation & interface provides " Has a" capability.

Preferuj implements Runnable :

  1. Jeśli nie musisz rozszerzać klasy Thread i modyfikować domyślnej implementacji Thread API
  2. jeśli wykonujesz ogień i zapomnij o komendzie
  3. Jeśli są już rozszerzające inną klasę

Preferuj "rozszerza wątek" :

  1. jeśli musisz nadpisać którąkolwiek z metod wątku wymienionych na stronie dokumentacji oracle

Generalnie nie trzeba nadpisywać zachowania wątku. Więc implementuje Runnable {[10] } jest preferowane przez większość czasu.

W innym przypadku użycie zaawansowanego API ExecutorService LUB ThreadPoolExecutorService zapewnia większą elastyczność i kontrolę.

Spójrz na to pytanie SE:

ExecutorService vs Casual Thread Spawner

 6
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:31

Różnica między rozszerzeniem wątku a implementacją Runnable to:

Tutaj wpisz opis obrazka

 6
Author: Raman Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-01 15:05:06

Oddzielenie klasy Thread od implementacji Runnable pozwala również uniknąć potencjalnych problemów z synchronizacją pomiędzy wątkiem a metodą run (). Oddzielny Runnable ogólnie daje większą elastyczność w sposobie, w jaki kod runnable jest odwoływany i wykonywany.

 5
Author: Govula Srinivas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 07:03:06

Jednym z powodów, dla których chcesz zaimplementować interfejs zamiast rozszerzać klasę bazową, jest to, że już rozszerzasz inną klasę. Możesz rozszerzyć tylko jedną klasę, ale możesz zaimplementować dowolną liczbę interfejsów.

Jeśli rozszerzasz wątek, w zasadzie uniemożliwiasz wykonanie logiki przez inny wątek niż 'this'. Jeśli chcesz tylko jakiś wątek do wykonania swojej logiki, lepiej zaimplementować Runnable.

 5
Author: Nikhil A A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 17:29:00

Jeśli używasz runnable, możesz zaoszczędzić miejsce, aby rozszerzyć je na inną klasę.

 5
Author: user2771655,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 05:58:02

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, po prostu chcieliśmy wykonać zadanie, najprawdopodobniej w trybie asynchronicznym, co dokładnie oznacza, że wykonanie zadania musi rozgałęziać się z naszego głównego wątku i głównego wątku, jeśli zakończy się wcześnie, może lub nie musi czekać na rozgałęzioną ścieżkę (zadanie).

Jeśli to jest cały cel, to gdzie widzę potrzebę wyspecjalizowanego wątku. Można to osiągnąć, podnosząc surowy Wątek z puli wątków systemu i przypisanie mu naszego zadania (może być instancją naszej klasy) i tyle.

Więc zastosujmy się do koncepcji OOPs I napiszmy klasę typu, którego potrzebujemy. Jest wiele sposobów na robienie rzeczy, robienie tego we właściwy sposób ma znaczenie.

Potrzebujemy zadania, więc napisz definicję zadania, którą można uruchomić w wątku. Więc użyj Runnable.

Zawsze pamiętaj {[1] } jest specjalnie używany do przekazywania zachowań i extends jest używany do przekazywania cecha / właściwość.

Nie chcemy właściwości wątku, zamiast tego chcemy, aby nasza klasa zachowywała się jak zadanie, które można uruchomić.

 5
Author: dharam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-22 03:11:51

Tak, Jeśli wywołujesz wywołanie threada, to nie musisz wywoływać metody start I run metoda jest wywołaniem po wywołaniu tylko klasy ThreadA. Ale jeśli użyjesz wywołania ThreadB, musisz użyć metody start thread for call run. Jeśli masz więcej pomocy, odpowiedz mi.

 4
Author: Manoj Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-28 08:31:16

Uważam, że najbardziej przydatne jest użycie Runnable ze wszystkich wymienionych powodów, ale czasami lubię rozszerzać wątek, aby móc utworzyć własną metodę zatrzymywania wątku i wywołać ją bezpośrednio w wątku, który stworzyłem.

 4
Author: Tarvaris Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-09 19:09:15

Java nie obsługuje wielu dziedziczeń, więc jeśli rozszerzysz klasę Thread, to żadna inna klasa nie zostanie rozszerzona.

Na przykład: jeśli tworzysz aplet, to musi on rozszerzyć klasę apletu, więc tutaj jedynym sposobem na utworzenie wątku jest implementacja Runnable interface

 4
Author: Himanshu Mohta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-09 19:28:31

To jestS zSOLID : pojedyncza odpowiedzialność.

A thread uosabia running context (jak w kontekście wykonania: ramka stosu, ID wątku itp.) asynchronicznego wykonania fragmentu kodu. Ten fragment kodu idealnie powinien być tą samą implementacją, niezależnie od tego, czy synchroniczny Czy asynchroniczny .

Jeśli połączysz je w jedną implementację, nadasz wynikowemu obiektowi dwa niezwiązane przyczyny zmian:

  1. obsługa wątków w Twojej aplikacji (np. zapytania i modyfikowanie kontekstu wykonania)
  2. algorytm zaimplementowany przez fragment kodu (część wykonywalną)

Jeśli język, którego używasz, obsługuje częściowe klasy lub dziedziczenie wielokrotne, możesz segregować każdą przyczynę w własną super klasę, ale sprowadza się to do tego samego, co komponowanie dwóch obiektów, ponieważ ich zestawy funkcji nie nakładają się na siebie. To do teorii.

W praktyce, ogólnie rzecz biorąc, program nie musi mieć większej złożoności niż jest to konieczne. Jeśli masz jeden wątek pracujący nad konkretnym zadaniem, bez zmiany tego zadania, prawdopodobnie nie ma sensu oddzielać zadań od klas, a Twój kod pozostaje prostszy.

W kontekścieJava , ponieważ obiekt jest już , prawdopodobnie łatwiej jest zacząć bezpośrednio od samodzielnych klas Runnable i przekazać ich instancje do Thread (lub Executor) instancje. Raz użyty do tego wzorca, nie jest trudniejszy w użyciu (ani nawet odczytaniu) niż prosta sprawa z wykonywalnym wątkiem.

 4
Author: didierc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-11 08:41:39

Różnica między Thread a runnable .Jeżeli tworzymy wątek używając klasy Thread to ilość wątku równa ilości wytworzonego obiektu . Jeśli tworzymy wątek implementując interfejs runnable to możemy użyć pojedynczego obiektu do tworzenia wielu thread.So pojedynczy obiekt jest współdzielony przez wiele Thread.So to zajmie mniej pamięci

Więc w zależności od wymagań, jeśli nasze dane nie są sensowne. Więc może być współdzielony między wieloma wątkami możemy użyć Runnable interfejs.

 4
Author: Rohit Chugh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-05 06:13:58

Dodaję tu moje dwa grosze - zawsze, gdy jest to możliwe, używaj implements Runnable . Poniżej znajdują się dwa zastrzeżenia, dlaczego nie należy używać extends Threads

  1. W idealnym przypadku nigdy nie należy rozszerzać klasy Thread; klasa Thread powinna być wykonana final. Przynajmniej jego metody jak thread.getId(). Zobacz to Dyskusja o błędzie związanym z rozszerzeniem Thread s.

  2. Ci, którzy lubią rozwiązywać zagadki, mogą zobaczyć kolejny efekt uboczny rozszerzenia wątku. Poniższy kod wydrukuje nieosiągalne kod, gdy nikt ich nie zawiadamia.

Zobacz http://pastebin.com/BjKNNs2G .

public class WaitPuzzle {

    public static void main(String[] args) throws InterruptedException {
        DoNothing doNothing = new DoNothing();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        Thread.sleep(100);
        doNothing.start();
        while(true) {
            Thread.sleep(10);
        }
    }


    static class WaitForever extends  Thread {

        private DoNothing doNothing;

        public WaitForever(DoNothing doNothing) {
            this.doNothing =  doNothing;
        }

        @Override
        public void run() {
            synchronized (doNothing) {
                try {
                    doNothing.wait(); // will wait forever here as nobody notifies here
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unreachable Code");
            }
        }
    }

    static class DoNothing extends Thread {

        @Override
        public void run() {
            System.out.println("Do Nothing ");
        }
    } 
}
 4
Author: veritas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-03 09:41:19

Jedną z różnic między implementacją Runnable i extended Thread jest to, że rozszerzając wątek, każdy z wątków ma przypisany do niego unikalny obiekt, podczas gdy implementacja Runnable, wiele wątków może współdzielić tę samą instancję obiektu.

Klasa, która implementuje Runnable, nie jest wątkiem, a tylko klasą. Aby Runnable był wykonywany przez wątek, musisz utworzyć instancję Thread i przekazać instancję Runnable jako cel.

W większości przypadków Runnable interfejs powinien być używany, jeśli tylko planujesz nadpisać metodę run() i nie ma innych metod wątku. Jest to ważne, ponieważ klasy nie powinny być podklasowane, chyba że programista zamierza zmodyfikować lub ulepszyć podstawowe zachowanie klasy.

Gdy istnieje potrzeba rozszerzenia klasy superclass, implementacja interfejsu Runnable jest bardziej odpowiednia niż użycie klasy Thread. Ponieważ możemy rozszerzyć inną klasę podczas implementacji interfejsu Runnable, aby utworzyć wątek. Ale jeśli tylko rozszerzymy klasę Thread, nie możemy dziedziczyć z żadnej innej klasy.

 4
Author: Vishal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-03 13:46:02