"реализует Runnable" vs "extends Thread" в Java - программирование

"реализует Runnable" vs "extends Thread" в Java

С какого времени я провел с потоками в Java, я нашел эти два способа записи потоков:

С implements Runnable:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

Или, с extends Thread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

Есть ли существенная разница в этих двух блоках кода?

4b9b3361

Ответ 1

Да: реализация Runnable - это предпочтительный способ сделать это, IMO. Вы не специализируетесь на поведении потоков. Вы просто даете ему что-то бежать. Это означает composition - философский "более чистый" путь.

В практическом плане это означает, что вы можете реализовать Runnable и перейти от другого класса.

Ответ 2

tl;dr: реализует Runnable лучше. Тем не менее, предостережение важно

В целом, я бы рекомендовал использовать что-то вроде Runnable, а не Thread, потому что это позволяет вам сохранить свою работу только в слабой связи с выбором параллелизма. Например, если вы используете Runnable и позже решите, что для этого фактически не требуется его собственный Thread, вы можете просто вызвать threadA.run().

Предостережение: Здесь я настоятельно не рекомендую использовать необработанные потоки. Я очень предпочитаю использовать Callables и FutureTasks (из javadoc: "отменяемые асинхронные вычисления"). Интеграция тайм-аутов, правильная отмена и объединение потоков в современной поддержке параллелизма гораздо более полезны для меня, чем груды необработанных потоков.

Продолжение: есть конструктор FutureTask, который позволяет вам использовать Runnables (если это то, с чем вам удобнее всего) и при этом пользоваться преимуществами современных инструментов параллелизма. Цитировать Javadoc:

Если вам не нужен конкретный результат, рассмотрите возможность использования конструкций вида:

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

Итак, если мы заменим их runnable на ваш threadA, мы получим следующее:

new FutureTask<Object>(threadA, null)

Другой вариант, позволяющий вам оставаться ближе к Runnables, - это ThreadPoolExecutor. Вы можете использовать метод execute, чтобы передать Runnable для выполнения "заданной задачи в будущем".

Если вы хотите попробовать использовать пул потоков, приведенный выше фрагмент кода будет выглядеть примерно так (при использовании Executors.newCachedThreadPool() фабричного метода):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

Ответ 3

Мораль истории:

Наследовать, только если вы хотите переопределить какое-либо поведение.

Или, скорее, его следует читать как:

Наследовать меньше, больше интерфейса.

Ответ 4

Ну, так много хороших ответов, я хочу добавить еще об этом. Это поможет понять Extending v/s Implementing Thread.
Extends очень тесно связывает два файла классов и может привести к некоторым трудностям при работе с кодом.

Оба подхода выполняют одну и ту же работу, но есть некоторые различия.
Наиболее распространенная разница

  1. Когда вы расширяете класс Thread, после этого вы не можете расширить любой другой класс, который вам требуется. (Как вы знаете, Java не позволяет наследовать более одного класса).
  2. Когда вы реализуете Runnable, вы можете сэкономить место для вашего класса, чтобы расширить любой другой класс в будущем или сейчас.

Однако одно существенное различие между реализацией Runnable и расширением Thread заключается в том, что
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.

Следующий пример поможет вам лучше понять

//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 the 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();
 }
}

Вывод вышеуказанной программы.

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

В подходе интерфейса Runnable создается только один экземпляр класса, и он используется разными потоками. Таким образом, значение счетчика увеличивается для каждого доступа к потоку.

Принимая во внимание, что подход класса Thread, вы должны создать отдельный экземпляр для каждого доступа потока. Следовательно, для каждого экземпляра класса выделяется разная память, и у каждого есть отдельный счетчик, значение остается тем же, что означает, что никакого приращения не произойдет, потому что ни одна из ссылок на объект не является одинаковой.

Когда использовать Runnable?
Используйте интерфейс Runnable, когда вы хотите получить доступ к тем же ресурсам из группы потоков. Избегайте использования класса Thread здесь, потому что создание нескольких объектов потребляет больше памяти, и это приводит к значительному снижению производительности.

Класс, который реализует Runnable, не является потоком, а просто классом. Чтобы Runnable стал потоком, вам нужно создать экземпляр потока и передать себя в качестве цели.

В большинстве случаев интерфейс Runnable следует использовать, если вы планируете переопределить только метод run() а не другие методы Thread. Это важно, потому что классы не должны быть разделены на подклассы, если программист не намеревается изменить или улучшить фундаментальное поведение класса.

Когда необходимо расширить суперкласс, реализация интерфейса Runnable более подходит, чем использование класса Thread. Потому что мы можем расширить другой класс при реализации интерфейса Runnable для создания потока.

Я надеюсь, это поможет!

Ответ 5

Одна вещь, которую я удивляю, еще не упоминалась, заключается в том, что реализация Runnable делает ваш класс более гибким.

Если вы расширяете поток, то действие, которое вы делаете, всегда будет в потоке. Однако, если вы реализуете Runnable, это не обязательно. Вы можете запустить его в потоке или передать его какой-либо службе-исполнителю или просто передать его как задачу в однопоточном приложении (возможно, для запуска позднее, но в пределах одного потока). Опции намного более открытые, если вы просто используете Runnable, чем если бы вы привязали себя к Thread.

Ответ 6

Если вы хотите реализовать или расширить любой другой класс, тогда интерфейс Runnable наиболее предпочтителен, в противном случае, если вы не хотите, чтобы какой-либо другой класс расширял или реализовывал, тогда класс Thread является предпочтительным.

Наиболее распространенная разница

enter image description here

Когда вы extends Thread класс extends Thread, после этого вы не можете расширять любой другой класс, который вам требуется. (Как вы знаете, Java не позволяет наследовать более одного класса).

Когда вы implements Runnable, вы можете сэкономить место для вашего класса, чтобы расширить любой другой класс в будущем или сейчас.

  • Java не поддерживает множественное наследование, что означает, что вы можете расширять только один класс в Java, поэтому, расширив класс Thread, вы потеряете свой шанс и не сможете расширять или наследовать другой класс в Java.

  • В объектно-ориентированном программировании расширение класса обычно означает добавление новой функциональности и изменение или улучшение поведения. Если мы не вносим никаких изменений в Thread, используйте вместо этого интерфейс Runnable.

  • Runnable интерфейс представляет собой задачу, которая может быть выполнена либо обычным потоком, либо исполнителями, либо любым другим способом. поэтому логическое разделение Task как Runnable чем Thread является хорошим дизайнерским решением.

  • Разделение задачи как Runnable означает, что мы можем повторно использовать задачу, а также имеем возможность выполнять ее различными способами. так как вы не можете перезапустить поток после его завершения. снова Runnable vs Thread для задачи, Runnable - победитель.

  • Разработчик Java признает это и то, почему Исполнители принимают Runnable как Задачу, и у них есть рабочий поток, который выполняет эту задачу.

  • Наследование всех методов Thread - это дополнительные издержки только для представления Задачи, которые можно легко выполнить с помощью Runnable.

Предоставлено javarevisited.blogspot.com

Это были некоторые заметные различия между Thread и Runnable в Java. Если вы знаете какие-либо отличия между Thread и Runnable, чем, пожалуйста, поделитесь им в комментариях. Я лично использую Runnable over Thread для этого сценария и рекомендую использовать интерфейс Runnable или Callable в зависимости от ваших требований.

Однако существенная разница есть.

Когда вы extends Thread класс extends Thread, каждый ваш поток создает уникальный объект и связывается с ним. Когда вы implements Runnable, он разделяет один и тот же объект на несколько потоков.

Ответ 7

Собственно, нецелесообразно сравнивать Runnable и Thread друг с другом.

У этих двух есть зависимость и взаимосвязь в многопоточности, как и отношение Wheel and Engine транспортного средства.

Я бы сказал, есть только один способ многопоточности с двумя шагами. Позвольте мне высказать свою мысль.

Runnable:
При реализации interface Runnable это означает, что вы создаете нечто, что run able в другом потоке. Теперь создание чего-то, что может выполняться внутри потока (runnable внутри потока), не означает создание потока.
Таким образом, класс MyRunnable представляет собой не что иное, как обычный класс с методом void run. И это объекты будут обычными объектами только с методом run, который будет нормально выполняться при вызове. (если мы не передадим объект в потоке).

Тема:
class Thread, я бы сказал, очень специальный класс с возможностью запуска нового потока, который фактически позволяет многопоточность через метод start().

Почему не разумно сравнивать?
Потому что нам нужны оба для многопоточности.

Для многопоточности нам нужны две вещи:

  • Что-то, что может работать внутри Thread (Runnable).
  • Что-то, что может начать новый поток (Thread).

Таким образом, технически и теоретически, оба из них необходимы для запуска потока, один из них будет запускать, а один будет запустит его (как Wheel and Engineсильным автомобилем).

Чтобы вы не могли начать поток с MyRunnable, вам нужно передать его в экземпляр Thread.

Но можно создать и запустить поток только с помощью class Thread, потому что Class Thread реализует Runnable, поэтому мы все знаем, что Thread также является Runnable внутри.

Наконец Thread и Runnable дополняют друг друга для многопоточности, а не для конкурента или замены.

Ответ 9

Я не эксперт, но могу придумать одну из причин для внедрения Runnable вместо расширения Thread: Java поддерживает только одно наследование, поэтому вы можете расширить только один класс.

Изменить: это изначально говорилось: "Для реализации интерфейса требуется меньше ресурсов". также, но вам нужно создать новый экземпляр Thread любым способом, так что это было неправильно.

Ответ 10

Я бы сказал, что есть третий способ:

public class Something {

    public void justAnotherMethod() { ... }

}

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

Возможно, это немного повлияло на мое недавнее интенсивное использование Javascript и Actionscript 3, но таким образом вашему классу не нужно реализовывать довольно смутный интерфейс, например Runnable.

Ответ 11

С выпуском Java 8 теперь есть третий вариант.

Runnable является функциональным интерфейсом , что означает, что его экземпляры могут быть созданы с помощью лямбда-выражений или ссылок на методы.

Ваш пример может быть заменен на:

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

или если вы хотите использовать ExecutorService и ссылку на метод:

executor.execute(runner::run)

Это не только намного короче, чем ваши примеры, но также приходят со многими преимуществами, изложенными в других ответах на использование Runnable over Thread, таких как единая ответственность и использование композиции, потому что вы не специализируетесь на потоке поведение. Этот способ также позволяет избежать создания дополнительного класса, если все, что вам нужно, это Runnable, как и в ваших примерах.

Ответ 12

Создание интерфейса дает более четкое разделение между вашим кодом и реализацией потоков, поэтому я предпочел бы реализовать Runnable в этом случае.

Ответ 13

Кажется, что все считают, что внедрение Runnable - это способ пойти, и я не согласен с ними, но есть также аргумент в пользу расширения Thread, по моему мнению, на самом деле вы его продемонстрировали в своем коде.

Если вы реализуете Runnable, тогда класс, который реализует Runnable, не имеет контроля над именем потока, это вызывающий код, который может установить имя потока, например:

new Thread(myRunnable,"WhateverNameiFeelLike");

но если вы продолжите Thread, тогда вы сможете управлять этим в самом классе (как и в вашем примере, вы называете поток ThreadB). В этом случае вы:

A) может дать ему более полезное имя для целей отладки

B) заставляют использовать это имя для всех экземпляров этого класса (если вы не игнорируете тот факт, что это поток, и делайте с ним выше, как если бы он был Runnable, но мы говорим о соглашении здесь в любом поэтому я могу игнорировать эту возможность).

Вы можете, например, взять трассировку стека из своего создания и использовать это как имя потока. Это может показаться странным, но в зависимости от того, как структурирован ваш код, он может быть очень полезен для целей отладки.

Это может показаться маленькой, но там, где у вас очень сложное приложение с большим количеством потоков, и внезапно все "остановилось" (либо по причинам тупика, либо, возможно, из-за недостатка в сетевом протоколе, который было бы менее очевидным - или другими бесконечными причинами), тогда получение дампа стека из Java, где все потоки называются "Thread-1", "Thread-2", "Thread-3", не всегда очень полезно (это зависит от того, как ваши потоки структурированы и можете ли вы с пользой сказать, что именно по их трассировке стека - не всегда возможно, если вы используете группы из нескольких потоков, все из которых работают с одним и тем же кодом).

Сказав, что вы, конечно же, можете сделать это в общем виде, создав расширение класса потока, которое устанавливает его имя в трассировку стека своего вызова создания, а затем использует его с вашими реализациями Runnable вместо стандартного java класс Thread (см. ниже), но в дополнение к трассировке стека может быть больше информации, специфичной для контекста, которая была бы полезной в имени потока для отладки (ссылка на одну из многих очередей или сокетов, которые она могла бы обрабатывать, например, в этом случае вы может предпочесть продлить Thread специально для этого случая, чтобы вы могли заставить компилятор заставить вас (или других пользователей, использующих ваши библиотеки) передавать определенную информацию (например, указанную очередь/сокет) для использования в имени).

Вот пример общего потока с трассировкой вызывающего стека как его имя:

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"));
    }
}

и здесь образец выходного файла, сравнивающий два имени:

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]

Ответ 14

  • Java не поддерживает множественное наследование, а это значит, что вы можете расширять только один класс на Java, поэтому, как только вы расширили класс Thread, вы потеряли свой шанс и не можете продлить или наследовать другой класс на Java.
  • В объектно-ориентированном программировании расширение класса обычно означает добавление новых функций, изменение или улучшение поведения. Если мы не вносим никаких изменений на Thread, а вместо этого используем интерфейс Runnable. Интерфейс
  • Runnable представляет собой Task, который может выполняться либо обычным Thread, либо Executors или любым другим способом. Поэтому логическое разделение Task как Runnable, чем Thread является хорошим конструктивным решением.
  • Разделительная задача как Runnable означает, что мы можем повторно использовать задачу, а также иметь возможность выполнять ее с разных средств. Поскольку вы не можете перезапустить Thread после завершения, снова Runnable vs Thread для задачи, Runnable является победителем.
  • Java-дизайнер распознает это и почему Executors принимает Runnable как Task, и у них есть рабочий поток, который выполняет эту задачу.
  • Наследование всех методов Thread - дополнительные накладные расходы только для представления Task, который можно легко выполнить с помощью Runnable.

Ответ 15

Runnable, потому что:

  • Предоставляет больше гибкости для Бегущая реализация для расширения другой класс
  • Отделяет код от выполнение
  • Позволяет запускать управляемый из пула потоков, поток событий или любым другим способом в будущее.

Даже если вам это не нужно сейчас, вы можете в будущем. Поскольку нет преимущества для переопределения Thread, Runnable - лучшее решение.

Ответ 16

Поскольку это очень популярная тема, и хорошие ответы распространяются повсюду и рассматриваются с большой глубиной, я счел оправданным составить хорошие ответы от других в более сжатые формы, так что новички имеют простой обзор авансовые:

  • Обычно вы добавляете класс для добавления или изменения функциональности. Итак, если вы не хотите перезаписывать любое поведение потока, используйте Runnable.

  • В том же свете, если вам не нужны методы наследовать, вы можете обойтись без служебных с помощью Runnable.

  • Одиночное наследование. Если вы расширяете тему Thread, вы не можете распространяться ни на один другой класс, поэтому, если это то, что вам нужно сделать, вам нужно использовать Runnable.

  • Хороший дизайн для разделения логики домена с помощью технических средств, в этом смысле лучше иметь задачу Runnable изолировать вашу задачу от вашего > бегун.

  • Вы можете выполнить один и тот же Runnable объект несколько раз, но объект Thread может быть запущен только один раз. (Может быть, причина, почему исполнители действительно принимают Runnables, но не Threads.)

  • Если вы разрабатываете свою задачу как Runnable, у вас есть гибкость, как использовать ее сейчас и в будущем. Вы можете запустить его одновременно с помощью Executors, но также через Thread. И вы все равно можете использовать/вызывать его не одновременно в пределах одного потока, как и любой другой обычный тип/объект.

  • Это облегчает разделить задачу-логику и concurrency аспекты ваших модульных тестов.

  • Если вас интересует этот вопрос, вас также может заинтересовать разница между Callable и Runnable.

Ответ 17

Разница между расширением потока и реализацией Runnable:

введите описание изображения здесь

Ответ 18

Это обсуждается в учебном пособии Oracle Определение и запуск потока:

Какую из этих идиом вы должны использовать? Первая идиома, в которой используется Runnable object, является более общим, поскольку объект Runnable может подкласс - класс, отличный от Thread. Вторая идиома проще в использовании в простых приложениях, но ограничивается тем, что ваша задача класс должен быть потомком Thread. Этот урок фокусируется на первом подход, который отделяет задачу Runnable от объекта Thread который выполняет задачу. Этот подход не только более гибкий, но он применим к API-интерфейсам управления потоками высокого уровня позже.

Другими словами, реализация Runnable будет работать в сценариях, где ваш класс расширяет класс, отличный от Thread. Java не поддерживает множественное наследование. Кроме того, расширение Thread будет невозможно при использовании некоторых высокоуровневых API управления потоками. Единственный сценарий, в котором расширение Thread предпочтительнее, - это небольшое приложение, которое в будущем не будет обновляться. Практически лучше реализовать Runnable, поскольку он более гибкий по мере роста вашего проекта. Изменение дизайна не окажет большого влияния, поскольку вы можете реализовать множество интерфейсов в java, но только расширяете один класс.

Ответ 19

Если я не ошибаюсь, он более или менее похож на

В чем разница между интерфейсом и абстрактным классом?

extends устанавливает " Is A" отношение и интерфейс обеспечивает " имеет".

Предпочитает реализует Runnable:

  • Если вам не нужно расширять класс Thread и изменять реализацию по умолчанию API нитей
  • Если вы выполняете пожар и забываете команду
  • Если вы уже расширяете другой класс

Предпочитаете " расширять поток":

  • Если вам нужно переопределить любой из этих Thread методов, перечисленных на странице документации oracle

Как правило, вам не нужно переопределять поведение Thread. Таким образом, реализует Runnable является предпочтительным в большинстве случаев.

С другой стороны, использование расширенного API ExecutorService или ThreadPoolExecutorService обеспечивает большую гибкость и контроль.

Взгляните на этот вопрос СЕ:

ExecutorService vs Casual Thread Spawner

Ответ 20

Самое простое объяснение состоит в том, что, реализуя Runnable мы можем назначить один и тот же объект нескольким потокам, и каждый Thread имеет одинаковые состояния и поведение объекта.

Например, предположим, что есть два потока, thread1 помещает целое число в массив, а thread2 берет целые числа из массива, когда массив заполняется. Обратите внимание, что для работы thread2 необходимо знать состояние массива, заполнил ли thread1 или нет.

Реализация Runnable позволяет вам иметь такую гибкость для совместного использования объекта, в то время как при расширении extends Thread вы можете создавать новые объекты для каждого потока, поэтому любое обновление, выполняемое thread1, теряется в thread2.

Ответ 21

Отделить класс Thread от реализации Runnable также позволяет избежать возможных проблем синхронизации между потоком и методом run(). Отдельный Runnable обычно обеспечивает большую гибкость в том, как ссылающийся и исполняемый код ссылается и выполняется.

Ответ 22

Это S из SOLID: единоличная ответственность.

Поток воплощает рабочий контекст (как в контексте выполнения: кадр стека, идентификатор потока и т.д.) Асинхронного выполнения фрагмента кода. Этот кусок кода в идеале должен быть одной и той же реализацией, будь то синхронный или асинхронный.

Если вы объедините их в одну реализацию, вы дадите результирующему объекту две несвязанные причины изменения:

  1. обработка потоков в вашем приложении (т.е. запрос и изменение контекста выполнения)
  2. Алгоритм, реализованный с помощью фрагмента кода (выполняемая часть)

Если используемый вами язык поддерживает частичные классы или множественное наследование, то вы можете отделить каждую причину в своем собственном суперклассе, но это сводится к тому же, что и составление двух объектов, поскольку их наборы функций не перекрываются. Это для теории.

На практике, вообще говоря, программа не должна нести больше сложности, чем необходимо. Если у вас есть один поток, работающий над конкретной задачей, не меняя ее, вероятно, нет смысла делать задачи отдельными классами, и ваш код остается более простым.

В контексте Java, поскольку средство уже существует, вероятно, проще начать непосредственно с отдельных классов Runnable и передавать их экземпляры экземплярам Thread (или Executor). После того, как вы привыкли к этому шаблону, его не сложнее использовать (или даже читать), чем в случае простого запускаемого потока.

Ответ 23

Одной из причин, по которой вы хотите реализовать интерфейс, а не расширять базовый класс, является то, что вы уже расширяете какой-либо другой класс. Вы можете расширить только один класс, но вы можете реализовать любое количество интерфейсов.

Если вы расширяете Thread, вы в основном препятствуете выполнению вашей логики любым другим потоком, чем 'this'. Если вы хотите, чтобы какой-либо поток выполнял вашу логику, лучше просто выполнить Runnable.

Ответ 24

если вы используете runnable, вы можете сохранить пространство, чтобы перейти к любому другому классу.

Ответ 25

Можем ли мы повторно посетить основную причину, по которой мы хотели, чтобы наш класс вел себя как Thread? Нет никакой причины, мы просто хотели выполнить задачу, скорее всего, в асинхронном режиме, что точно означает, что выполнение задачи должно входить из нашего основного потока и основного потока, если заканчивается раньше, может или не может ждать для разветвленного пути (задачи).

Если это целая цель, то где я вижу потребность в специализированном потоке. Это может быть достигнуто путем сбора RAW-потока из пула системных потоков и назначения его нашей задачи (может быть экземпляром нашего класса), и это все.

Итак, давайте повинуемся концепции ООП и напишем класс типа, который нам нужен. Есть много способов сделать что-то, делайте это правильно.

Нам нужна задача, поэтому напишите определение задачи, которое можно запустить в потоке. Поэтому используйте Runnable.

Всегда помнить implements специально используется для придания поведения, а extends используется для передачи функции/свойства.

Нам не нужно свойство потока, вместо этого мы хотим, чтобы наш класс вел себя как задача, которая может быть запущена.

Ответ 26

Да, Если вы вызываете вызов ThreadA, тогда не нужно вызывать метод start, а метод run - это вызов после вызова класса ThreadA. Но если использовать ThreadB-вызов, тогда необходимо создать начальный поток для метода вызова. Если у вас есть дополнительная помощь, ответьте мне.

Ответ 27

Я считаю, что наиболее полезно использовать Runnable для всех упомянутых причин, но иногда мне нравится продлить Thread, поэтому я могу создать свой собственный метод остановки потока и вызвать его непосредственно на созданном мной потоке.

Ответ 28

Java не поддерживает множественную наследование, поэтому, если вы расширяете класс Thread, тогда никакой другой класс не будет расширен.

Например: если вы создаете апплет, то он должен расширять класс Applet, поэтому здесь единственный способ создать поток - реализовать интерфейс Runnable

Ответ 29

Runnable - это интерфейс, а Thread - класс, реализующий этот интерфейс. С точки зрения дизайна, должно быть чистое разделение между тем, как определяется задача и между тем, как она выполняется. Первый отвечает за реализацию Runnalbe, а последняя - в классе Thread. В большинстве случаев реализация Runnable - правильный путь.

Ответ 30

Разница между потоком и runnable . Если мы создаем Thread с использованием класса Thread, тогда количество потоков равно количеству созданного нами объекта. Если мы создаем поток, реализуя интерфейс runnable, мы можем использовать один объект для создания нескольких потоков. Один объект разделяется несколькими Thread.So он будет потреблять меньше памяти

Таким образом, в зависимости от требования, если наши данные не являются senstive. Таким образом, он может быть разделен между несколькими Thread, которые мы можем использовать интерфейс Runnable.