& ldquo; реализует Runnable & rdquo; vs & ldquo; extends Thread & rdquo; на Яве

Если вы пытаетесь сделать это в PCL Portable Class Library (например, я), то вот как вы можете это сделать:)

public class Foo
{
   public string A {get;set;}

   [Special]
   public string B {get;set;}   
}

var type = typeof(Foo);

var specialProperties = type.GetRuntimeProperties()
     .Where(pi => pi.PropertyType == typeof (string) 
      && pi.GetCustomAttributes<Special>(true).Any());

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

1957
задан Steve Chambers 11 September 2018 в 14:56
поделиться

21 ответ

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

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

1592
ответ дан Gray 12 September 2018 в 00:56
поделиться
  • 1
    Это все еще оставляет проблему текста расположенной неправильно. И it' s все еще изменение в SDK, который будет переопределен, если sdk будет обновлен когда-нибудь – ozba 5 September 2012 в 12:31

Я бы сказал, что реальная задача отделена от потока. Мы можем передать задачу в Thread, среду Executor и т. Д. В случае Runnable, в то время как с расширением Thread задача связана с самим объектом потока. Изоляция задачи не может быть выполнена в случае расширения Thread. Это похоже на то, что мы записываем задачу в объект Thread, просто как микросхему (и, более конкретно, не получим никакого дескриптора задачи).

0
ответ дан Pang 11 September 2018 в 14:56
поделиться

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

5
ответ дан user2771655 11 September 2018 в 14:56
поделиться

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

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

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

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

248
ответ дан Francesco Menzani 11 September 2018 в 14:56
поделиться

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

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

76
ответ дан Andrew Tobilko 11 September 2018 в 14:56
поделиться

Класс потока определяет несколько методов, которые могут быть overriden расширяющим классом. Но чтобы создать поток, мы должны переопределить метод run(). То же самое относится и к Runnable.

Однако Runnable является предпочтительным методом создания потока. Основные причины:

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

  2. Если вы не модифицируете или не расширяете множество функций Thread, то расширение класса Thread не является предпочтительным способом.

1
ответ дан Pritam Banerjee 11 September 2018 в 14:56
поделиться

Вы можете использовать их совместно

Пример:

public class A implements Runnable{

    @Override
    public void run() {


        while(true){
             System.out.println("Class A is running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }}

    }

}



public class Test {

    public static void main(String[] args) {

        Thread myThread =new Thread(new A());// 1
        myThread.start();
        System.out.println(" executed after thread A");//will never be reached

    }

} 
-1
ответ дан Java Main 11 September 2018 в 14:56
поделиться

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

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

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

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

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

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

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

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

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

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

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

]

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

67
ответ дан Saif 11 September 2018 в 14:56
поделиться

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

Наиболее существенное различие между реализацией Runnable и расширением Thread приведено ниже:

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

2
ответ дан rashedcs 11 September 2018 в 14:56
поделиться

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

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

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

6
ответ дан Shababb Karim 11 September 2018 в 14:56
поделиться

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

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

5
ответ дан Nikhil A A 11 September 2018 в 14:56
поделиться

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

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

32
ответ дан Powerlord 11 September 2018 в 14:56
поделиться

Различия между расширяющейся нитью и реализуемым Runnable:

enter image description here

8
ответ дан Raman Gupta 11 September 2018 в 14:56
поделиться

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

5
ответ дан Govula Srinivas 11 September 2018 в 14:56
поделиться

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

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

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

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

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

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

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

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

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

10
ответ дан Community 11 September 2018 в 14:56
поделиться

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

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

new Thread(myRunnable,"WhateverNameiFeelLike");

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

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

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

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

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

Сказав, что вы, конечно, также можете сделать вышеупомянутое универсальным способом, создав расширение класса потока, которое устанавливает его имя в виде трассировки стека его вызова создания, а затем использует это с вашими реализациями Runnable вместо стандартного Класс потока Java (см. ниже), но в дополнение к трассировке стека может быть более специфичная для контекста информация, которая будет полезна в имени потока для отладки (ссылка на одну из множества очередей или сокетов, которые он может обработать, например, в этом случае вы может предпочесть расширить 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]
11
ответ дан AntonyM 11 September 2018 в 14:56
поделиться

Поток хранит поведение, которое не предназначено для доступа;

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

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

public class ThreadMain {
    public int getId() {
        return 12345678;
    }

    public String getName() {
        return "Hello World";
    }

    public String getState() {
        return "testing";
    }

    public void example() {
        new Thread() {
            @Override
            public void run() {
                System.out.println("id: "+getId()+", name: "+getName()+", state: "+getState());
            }
        }.start();
    }

    public static void main(String[] args) {
        new ThreadMain().example();
    }
}

Если вы запустите это, вы можете ожидать

id: 12345678, name: Hello World, state: testing

, однако, вы не вызываете методы, как вы думаете, потому что вы используете метод в Thread не ThreadMain, а вместо этого Вы видите что-то вроде

id: 11, name: Thread-0, state: RUNNABLE
3
ответ дан Peter Lawrey 11 September 2018 в 14:56
поделиться

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

16
ответ дан starblue 12 September 2018 в 00:56
поделиться
  • 1
    @ShikhaShah, который getObject метод, который возвращает S3Object, от интерфейс AmazonS3 , который реализован AmazonS3Client. Возможно, Ваш IDE doesn' t показывают методы, наследованные от интерфейса? – Eyal 25 April 2013 в 08:02

Необходимо реализовать Выполнимый, но если Вы работаете на Java 5 или выше, Вы не должны запускать его с new Thread, но использовать ExecutorService вместо этого. Для получения дополнительной информации см.: , Как реализовать простую поточную обработку в Java.

44
ответ дан Community 12 September 2018 в 00:56
поделиться
  • 1
    См. другие ответы для фактического объяснения того, почему Вам нужен $ .is (). – pettazz 1 December 2010 в 06:03

tl; доктор: Выполнимые реализации лучше. Однако протест важен

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

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

Продолжение: существует FutureTask конструктор , который позволяет Вам использовать Runnables (если это - то, что Вы являетесь самыми довольными), и все еще извлеките пользу из современных инструментов параллелизма. Для заключения в кавычки javadoc:

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

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

Так, если мы заменяем их runnable Вашим threadA, мы получаем следующее:

new FutureTask<Object>(threadA, null)

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

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

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
540
ответ дан Bob Cross 12 September 2018 в 00:56
поделиться

Выполнение, потому что:

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

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

11
ответ дан 22 November 2019 в 19:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: