Вопрос

За время, проведенное с потоками в 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 лучше.Однако важно сделать оговорку

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

Предостережение: Здесь я настоятельно не рекомендую использовать необработанные потоки.Я предпочитаю использовать Вызовы и Будущие задачи (Из Javadoc:«Отменяемое асинхронное вычисление»).Интеграция таймаутов, правильная отмена и объединение потоков современной поддержки параллелизма — все это для меня гораздо полезнее, чем куча необработанных потоков.

Следовать за: Eсть FutureTask конструктор это позволяет вам использовать Runnables (если это вам наиболее удобно) и при этом получать преимущества современных инструментов параллелизма. Цитировать javadoc:

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

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

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

new FutureTask<Object>(threadA, null)

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

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

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

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

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

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

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

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

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

  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 для создания потока.

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

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

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

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

Наиболее распространенное различие заключается в

enter image description here

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

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

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

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

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

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

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

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

Любезно предоставлено javarevisited.blogspot.com

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вам следует реализовать Runnable, но если вы работаете на Java 5 или выше, вам не следует запускать его с помощью new Thread но используйте ИсполнительСервис вместо.Подробности см.: Как реализовать простую многопоточность в Java.

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

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

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

public class Something {

    public void justAnotherMethod() { ... }

}

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

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

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

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

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

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

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

executor.execute(runner::run)

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

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

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

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

new Thread(myRunnable,"WhateverNameiFeelLike");

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

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

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]

Работоспособен, потому что:

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

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

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

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

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

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

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

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

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

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

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

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

enter image description here

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

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

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

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

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

расширяет устанавливает "Это"Отношения и интерфейс обеспечивают"Имеет"возможность.

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

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

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

  1. Если вам нужно переопределить что-либо из этого Нить методы, перечисленные на странице документации Oracle.

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

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

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

ExecutorService против обычного создателя потоков

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

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

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

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

Это С из ТВЕРДЫЙ:Единая ответственность.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Добавляю сюда свои два цента -Всегда по возможности используйте implements Runnable .Ниже приведены два предостережения о том, почему вам не следует использоватьextends Threadс

  1. В идеале вам никогда не следует расширять класс Thread;тот Thread класс должен быть сделан final.По крайней мере, его методы, такие как thread.getId().Видеть этот обсуждение ошибки, связанной с расширением Threadс.

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

Пожалуйста, посмотри 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 ");
        }
    } 
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top