описание - thread runnable difference java




«Реализует Runnable» vs «extends Thread» в Java (20)

  1. Java не поддерживает множественное наследование, а это означает, что вы можете продлить один класс только на Java, поэтому, как только вы расширили класс Thread вы потеряли свой шанс и не можете расширять или наследовать другой класс на Java.
  2. В объектно-ориентированном программировании расширение класса обычно означает добавление новых функций, изменение или улучшение поведения. Если мы не вносим никаких изменений в Thread а вместо этого используем интерфейс Runnable .
  3. Runnable interface представляет собой Task которая может выполняться либо простым Thread либо Executors либо любыми другими способами. Таким образом, логическое разделение Task как Runnable than Thread - хорошее дизайнерское решение.
  4. Разделение задачи как Runnable означает, что мы можем повторно использовать задачу, а также иметь возможность выполнять ее с разных средств. Поскольку вы не можете перезапустить Thread после его завершения, снова Runnable vs Thread для задачи, Runnable является победителем.
  5. Дизайнер Java признает это, и поэтому Executors принимают Runnable as Task и у них есть рабочий поток, который выполняет эту задачу.
  6. Наследование всех методов Thread - это дополнительные накладные расходы только для представления Task которую можно легко выполнить с помощью Runnable .

С какого времени я провел с потоками в 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

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


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

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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


На самом деле, Runnable сравнивать Runnable и Thread друг с другом.

Эти два имеют зависимость и взаимосвязь в многопоточности, как отношения Wheel and Engine автомобиля.

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

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

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

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

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

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

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

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

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

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


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

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


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

  1. Обычно вы добавляете класс для добавления или изменения функциональности. Поэтому, если вы не хотите перезаписывать какое-либо поведение Thread , используйте Runnable.

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

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

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

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

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

  7. Это также упрощает разделение задач логики и параллелизма в ваших модульных тестах .

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


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


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

public class Something {

    public void justAnotherMethod() { ... }

}

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

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


tl; dr: реализует Runnable лучше. Однако оговорка важна

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

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

Последующие действия: существует конструктор 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());

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

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


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

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

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

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


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


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


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


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

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

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

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

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

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


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

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


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

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


Это S из SOLID : Single ответственность.

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

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

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

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

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

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







java-threads