Зачем использовать класс thread, когда мы запускаем интерфейс в java? [Дубликат]

Вот чистое решение html / css:

HTML

This entire box is a hyperlink. (Kind of)



I'm a W3C compliant hyperlink inside that box

CSS

.block {
  position:relative;
}

.block .overlay {
  position:absolute;
  left:0; top:0; bottom:0; right:0;
}

.block .inner {
  position:relative;
  pointer-events: none;
  z-index: 1;
}

.block .inner a {
  pointer-events: all;
}

https://codepen.io / pwkip / ручка / oGMZjb

1815
задан Aditya W 18 October 2016 в 15:06
поделиться

30 ответов

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

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

1447
ответ дан Gray 17 August 2018 в 10:49
поделиться
  • 1
    Точно, хорошо. Какое поведение мы пытаемся переписать в Thread, расширив его? Я бы сказал, что большинство людей не пытается переписать какое-либо поведение, но пытается использовать поведение Thread. – hooknc 12 February 2009 в 17:50
  • 2
    В качестве побочного комментария, если вы создаете экземпляр Thread и не вызываете его метод start (), вы создаете утечку памяти в Java & lt; 5 (это не происходит с Runnables): stackoverflow.com/questions/107823/… – Nacho Coloma 7 February 2013 в 15:48
  • 3
    Одним из незначительных преимуществ Runnable является то, что если в определенных обстоятельствах вам неинтересно или не хотят использовать потоки, и вы просто хотите выполнить код, у вас есть возможность просто вызвать run (). например (очень ручной) if (numberCores > 4) myExecutor.excute(myRunnable); else myRunnable.run() – user949300 6 March 2013 в 21:30
  • 4
    @ user949300 вы также можете сделать это с помощью extends Thread, и если вам не нужна потоковая передача, почему бы вы даже реализовать Runnable ... – m0skit0 23 April 2013 в 09:15
  • 5
    Перефразируя Сьерра и Бейтса, ключевым преимуществом внедрения Runnable является то, что вы архитектурно разделяете «работу», от «бегуна». – 8bitjunkie 12 February 2014 в 11:28

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

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

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

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

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

executor.execute(runner::run)

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

16
ответ дан Alex 17 August 2018 в 10:49
поделиться
  • 1
    Этот ответ нуждается в объяснении. После некоторого озадачивания я пришел к выводу, что () -> {} должен представлять пользовательскую логику, которая кому-то нужна? Так лучше было бы сказать как () -> { /* Code here */ }? – ToolmakerSteve 5 September 2015 в 11:56
  • 2
    @ToolmakerSteve да, отредактирован. – Alex 5 September 2015 в 11:59

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

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

73
ответ дан Andrew Tobilko 17 August 2018 в 10:49
поделиться
  • 1
    Ну, вы действительно можете сделать то же самое с объектом Thread, потому что Thread implements Runnable ... ;-) Но он «чувствует себя лучше». делая это с помощью Runnable, чем с помощью Thread! – siegi 26 April 2012 в 22:13
  • 2
    Правда, но Thread добавляет много лишних вещей, которые вам не нужны, и во многих случаях не хотят. Вам всегда лучше реализовать интерфейс, который соответствует тому, что вы на самом деле делаете. – Herms 27 April 2012 в 14:19

Кажется, все здесь думают, что внедрение 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]
10
ответ дан AntonyM 17 August 2018 в 10:49
поделиться
  • 1
    Thread.currentThread().setName("WhateverNameiFeelLike"); – cHao 1 November 2012 в 18:53
  • 2
    cHao, что вы думаете? Вы не могли использовать свой код выше во время выполнения потока для получения stacktrace создания потоков (вместо этого вы получили бы простое имя или в лучшем случае stacktrace запуска потоков), но путем подкласса потока вы можете сделать именно это и заставить он даже требует дополнительной информации, специфичной для контекста, тем самым давая вам более конкретное представление о том, в какой именно теме может возникнуть проблема. – AntonyM 2 November 2012 в 15:56
  • 3
    Я хочу сказать, что «Если вы реализуете Runnable, тогда класс, реализующий Runnable, не имеет контроля над именем потока ... & quot; явно ложно. Класс, реализующий Runnable, действительно может управлять именем потока, поскольку поток, выполняющий код, по определению имеет текущий поток (и любой код, который проходит проверки безопасности , имеет контроль над именами потоков). Учитывая, что вы посвящаете половину своего сообщения «omg, как насчет имен нитей!», Это похоже на нечто вроде большой сделки. – cHao 2 November 2012 в 16:02
  • 4
    Имя потока? Ничто не мешает вам расширить класс потоков. – RichieHH 28 July 2014 в 03:59

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

public class Something {

    public void justAnotherMethod() { ... }

}

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

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

19
ответ дан Bart van Heukelom 17 August 2018 в 10:49
поделиться
  • 1
    Это не третий путь. Вы все еще используете Runnable, просто делаете это анонимно. – Don Roby 12 January 2011 в 19:50
  • 2
    @Don Roby: Что другое. Это часто удобно, и вы можете использовать поля и конечные локальные переменные из содержащего класса / метода. – Bart van Heukelom 13 January 2011 в 10:59
  • 3
    Да, это удобно. – Don Roby 13 January 2011 в 11:21
  • 4
    @BartvanHeukelom Это удобно, но не совсем так. Вы можете сделать это с помощью любого типа вложенного класса, то есть внутренних классов, локальных классов и лямбда-выражений. – xehpuk 6 January 2015 в 02:28

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

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

extends устанавливает " Является отношением & amp; реализует Runnable :

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

Предпочитаете « extends Thread ":

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

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

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

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

ExecutorService vs Casual Thread Spawner

41
ответ дан Community 17 August 2018 в 10:49
поделиться
  • 1
    Я бы не подумал, что ExecutorService будет полезен, если вы просто хотите запустить один поток. – Powerlord 12 February 2009 в 15:54
  • 2
    Из того, что я узнал, вы больше не должны запускать нить самостоятельно, потому что оставляя это для службы-исполнителя, делает все гораздо более управляемым (например, ожидая приостановления потока). Кроме того, я ничего не вижу в вопросе, который подразумевает, что речь идет об одном потоке. – Fabian Steeg 12 February 2009 в 16:16
  • 3
    Какой смысл использовать многопоточность, если мы знаем aprior, что это будет единственный поток. Итак, допустим, у нас есть несколько потоков, и этот ответ ценен. – zEro 22 June 2013 в 22:16
  • 4
    @zEro Я уверен, что есть причина, что есть только одна тема Dispatch. Я сомневаюсь, что это единственный случай, когда лучше иметь отдельный поток, но, возможно, не лучше иметь несколько. – porcoesphino 23 December 2013 в 17:07
  • 5
    О пункте № 5: Thread реализует Runnable. – Pino 28 April 2016 в 15:42
  • 6
    @Pino Да, сам поток также является Runnable. Однако, если вы расширите его, чтобы просто использовать его как Runnable, в чем смысл? Почему бы просто не использовать простой Runnable без всякого багажа. Итак, я бы сказал, что если вы продолжите Thread, вы также выполнили бы его, используя его метод start, который можно использовать только один раз. Это то, что Нидхиш-Кришнан хотел сделать в своем ответе. Обратите внимание, что моя - это просто компиляция или краткое резюме других ответов здесь. – Jörg 29 April 2016 в 10:15

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

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

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

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

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

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

5
ответ дан dharam 17 August 2018 в 10:49
поделиться

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

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

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

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

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

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

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

4
ответ дан didierc 17 August 2018 в 10:49
поделиться

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

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

enter image description here [/g1]

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

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

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

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

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

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

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

65
ответ дан Eftekhari 17 August 2018 в 10:49
поделиться

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

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

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

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

227
ответ дан Francesco Menzani 17 August 2018 в 10:49
поделиться
  • 1
    Это всегда должно быть вопросом, если вы начнете делать одновременно выполняющийся Object! Вам даже нужны функции Thread Object? – Liebertee 21 October 2015 в 07:59
  • 2
    При наследовании от Thread каждый почти всегда хочет переопределить поведение метода run(). – Warren Dew 7 June 2016 в 04:01
  • 3
    Вы не можете переопределить поведение функции java.lang.Thread, переопределив метод run(). В этом случае вам нужно переопределить метод start(), я думаю. Обычно вы просто повторно используете поведение java.lang.Thread, вводя ваш блок выполнения в метод run(). – sura2k 6 July 2016 в 09:28
  • 4

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

5
ответ дан Govula Srinivas 17 August 2018 в 10:49
поделиться

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

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

4
ответ дан Himanshu Mohta 17 August 2018 в 10:49
поделиться

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

  1. В идеале вы никогда не должны расширять класс Thread; класс Thread должен быть сделан final. По крайней мере, такие методы, как thread.getId(). См. это обсуждение для ошибки, связанной с расширением Thread s.
  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 ");
        }
    } 
}
4
ответ дан kinbiko 17 August 2018 в 10:49
поделиться

Ну так много хороших ответов, я хочу добавить еще об этом. Это поможет понять 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 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 стал потоком, вам нужно создать экземпляр Thread и передать себя в качестве цели.

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

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

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

185
ответ дан L Joey 17 August 2018 в 10:49
поделиться
  • 1
    Ваш код явно ошибочен. Я имею в виду, он делает то, что делает, но не то, что вы намеревались показать. – zEro 10 June 2013 в 07:25
  • 2
    Чтобы пояснить: для исполняемого файла вы использовали тот же экземпляр ImplementsRunnable для запуска нескольких потоков, тогда как для случая Thread вы создаете разные экземпляры ExtendsThread, что, очевидно, ведет к поведению, которое вы показали. Вторая половина вашего основного метода должна быть: ExtendsThread et = new ExtendsThread(); Thread tc1 = new Thread(et); tc1.start(); Thread.sleep(1000); Thread tc2 = new Thread(et); tc2.start(); Thread.sleep(1000); Thread tc3 = new Thread(et); tc3.start(); Насколько яснее? – zEro 10 June 2013 в 07:31
  • 3
    Я еще не понимаю ваших намерений, но я хотел сказать, что если вы создадите несколько экземпляров ExtendsThread - все они вернутся 1 (как вы показали). Вы можете получить те же результаты для Runnable, выполнив то же самое, т. Е. Создав несколько экземпляров ImplementsRunnable. – zEro 10 June 2013 в 13:29
  • 4
    @zEro Привет, я из будущего. Учитывая, что ваша версия кода имеет 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 неправильным? Если нет, то что такое случай, демонстрирующий это? – Evil Washing Machine 9 February 2015 в 12:23
  • 5
    @EvilWashingMachine: долгое время неактивно .. и просто увидел это. Я добавил хэш-код объекта в операторы печати ... + " hashcode: " + this.hashCode() – zEro 18 May 2015 в 20:07

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

4
ответ дан Manoj Kumar 17 August 2018 в 10:49
поделиться

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

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

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

10
ответ дан n13 17 August 2018 в 10:49
поделиться

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

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

5
ответ дан Nikhil A A 17 August 2018 в 10:49
поделиться
  • 1
    Да, реализуя интерфейс Runnable, можно свободно реализовать свою собственную логику, расширив любой класс, поэтому Runnable в основном предпочитает класс Thread. – Akash5288 4 December 2013 в 08:11

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

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

31
ответ дан Powerlord 17 August 2018 в 10:49
поделиться
  • 1
    В runnable мы не можем делать сетевые звонки, не так ли? Поскольку у меня есть android.os.NetworkOnMainThreadException. Но, используя поток, я могу делать сетевые вызовы. Пожалуйста, поправьте меня, если я ошибаюсь. – Nabeel Thobani 16 October 2014 в 06:16
  • 2
    @NabeelThobani Нормальная Java не волнует, но это звучит как Android. Однако я не достаточно хорошо знаком с Android. – Powerlord 16 October 2014 в 14:15
  • 3
    @NabeelThobani Конечно, вы можете. Возможно, вы не создаете Thread с помощью Runnable. – m0skit0 8 January 2015 в 20:11

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

6
ответ дан Raman Gupta 17 August 2018 в 10:49
поделиться

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());
494
ответ дан Ravindra babu 17 August 2018 в 10:49
поделиться
  • 1
    Это лучше, чем принятый ответ IMHO. Одна вещь: фрагмент кода, который у вас есть, не закрывает исполнителя, и я вижу миллионы вопросов, где люди ошибаются, создавая новый Исполнитель каждый раз, когда они хотят создать задачу. es будет лучше как статическое (или введенное) поле, так что он будет создан только один раз. – artbristol 19 November 2012 в 13:27
  • 2
    @artbristol, спасибо! Я не согласен с новым Исполнителем (мы делаем то, что вы предлагаете в нашем коде). При написании исходного ответа я пытался написать минимальный код, сравнимый с исходным фрагментом. Мы должны надеяться, что многие читатели этих ответов используют их в качестве прыжков с очков. Я не пытаюсь написать замену javadoc. Я эффективно пишу маркетинговые материалы для него: , если вам нравится этот метод, вы должны увидеть все другие замечательные вещи, которые мы можем предложить ...! – Bob Cross 19 November 2012 в 15:28
  • 3
    Я знаю, что я немного поздно комментирую это, но иметь дело с FutureTask напрямую, как правило, не то, что вы хотите сделать. ExecutorService s создаст для вас соответствующий Future, если вы submit a Runnable / Callable к ним. Аналогично для ScheduledExecutorService s и ScheduledFuture, когда вы schedule a Runnable / Callable. – Powerlord 28 April 2015 в 13:44
  • 4
    @Powerlord, я собирался сделать фрагменты кода, которые соответствовали OP как можно ближе. Я согласен с тем, что новый FutureTask не является оптимальным, но это понятно для целей объяснения. – Bob Cross 28 April 2015 в 17:04

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

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

4
ответ дан Rohit Chugh 17 August 2018 в 10:49
поделиться

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

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

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

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

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

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

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

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

Так что технически и теоретически оба из них необходимы, чтобы начать поток, один запустится, и один сделает

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

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

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

61
ответ дан Saif 17 August 2018 в 10:49
поделиться
  • 1
    В точку! Это должен быть принятый ответ. BTW Я думаю, что вопрос был отредактирован, а ThreadA больше не имеет смысла – idelvall 22 March 2016 в 17:51
  • 2
    принятый ответ гораздо больше делегата, спасибо за ответ @idelvall – Saif 22 March 2016 в 18:10
  1. Java не поддерживает множественное наследование, а это значит, что вы можете расширять только один класс на Java, поэтому, как только вы расширили Thread класс, вы потеряли свой шанс и не можете расширять или наследовать другой класс на Java.
  2. В объектно-ориентированном программировании расширение класса обычно означает добавление новых функций, изменение или улучшение поведения. Если мы не делаем каких-либо изменений на Thread, чем используем интерфейс Runnable. Интерфейс
  3. Runnable представляет собой Task, который может быть выполнен либо обычным Thread, либо Executors или любые другие средства. Таким образом, логическое разделение Task как Runnable, чем Thread, является хорошим конструктивным решением.
  4. Отделяющая задача как Runnable означает, что мы можем повторно использовать задачу, а также иметь возможность выполнять ее с разных средств. Поскольку вы не можете перезапустить Thread после его завершения, снова Runnable vs Thread для задачи, Runnable является победителем.
  5. Разработчик Java распознает это, и именно поэтому Executors принимает Runnable ] как Task, и у них есть рабочий поток, который выполняет эту задачу.
  6. Наследование всех методов Thread - дополнительные накладные расходы только для представления функции Task, которая может быть легко выполнена с помощью Runnable.
12
ответ дан Sergey Brunov 17 August 2018 в 10:49
поделиться

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

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

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

8
ответ дан Sionnach733 17 August 2018 в 10:49
поделиться

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

15
ответ дан starblue 17 August 2018 в 10:49
поделиться

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

4
ответ дан Tarvaris Jackson 17 August 2018 в 10:49
поделиться

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

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

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

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

4
ответ дан Tyler B. Long 17 August 2018 в 10:49
поделиться

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

5
ответ дан user2771655 17 August 2018 в 10:49
поделиться

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

  1. Обычно вы добавляете класс для добавления или изменения функциональности. Итак, , если вы не хотите, чтобы перезаписывал любое поведение Thread, используйте Runnable.
  2. В том же свете , если вам не нужно чтобы наследовать методы потоков, вы можете обойтись без этих накладных расходов, используя Runnable.
  3. Одиночное наследование: если вы расширяете Thread, вы не можете распространяться ни на один другой класс, поэтому, если это то, что вам нужно сделать, вам нужно используйте Runnable.
  4. Хороший дизайн для разделения логики домена с помощью технических средств, в этом смысле лучше иметь задачу Runnable, изолирующую вашу задачу от вашего бегуна.
  5. Вы можете выполнить один и тот же объект Runnable несколько раз, объект Thread, однако, может быть запущен только один раз. (Может быть, причина, по которой Исполнители принимают Runnables, но не Threads.)
  6. Если вы разрабатываете свою задачу как Runnable, у вас есть все гибкость, как ее использовать сейчас и в будущем. Вы можете запустить его одновременно с помощью Executors, но также через Thread. И вы все равно можете использовать / вызывать его не одновременно в пределах одного потока, как и любой другой обычный тип / объект.
  7. Это также упрощает разделение задач логики и параллелизма в модульных тестах.
  8. Если вас интересует этот вопрос, вас также может заинтересовать разница между Callable и Runnable .
41
ответ дан Community 17 August 2018 в 10:49
поделиться
  • 1
    Я бы не подумал, что ExecutorService будет полезен, если вы просто хотите запустить один поток. – Powerlord 12 February 2009 в 15:54
  • 2
    Из того, что я узнал, вы больше не должны запускать нить самостоятельно, потому что оставляя это для службы-исполнителя, делает все гораздо более управляемым (например, ожидая приостановления потока). Кроме того, я ничего не вижу в вопросе, который подразумевает, что речь идет об одном потоке. – Fabian Steeg 12 February 2009 в 16:16
  • 3
    Какой смысл использовать многопоточность, если мы знаем aprior, что это будет единственный поток. Итак, допустим, у нас есть несколько потоков, и этот ответ ценен. – zEro 22 June 2013 в 22:16
  • 4
    @zEro Я уверен, что есть причина, что есть только одна тема Dispatch. Я сомневаюсь, что это единственный случай, когда лучше иметь отдельный поток, но, возможно, не лучше иметь несколько. – porcoesphino 23 December 2013 в 17:07
  • 5
    О пункте № 5: Thread реализует Runnable. – Pino 28 April 2016 в 15:42
  • 6
    @Pino Да, сам поток также является Runnable. Однако, если вы расширите его, чтобы просто использовать его как Runnable, в чем смысл? Почему бы просто не использовать простой Runnable без всякого багажа. Итак, я бы сказал, что если вы продолжите Thread, вы также выполнили бы его, используя его метод start, который можно использовать только один раз. Это то, что Нидхиш-Кришнан хотел сделать в своем ответе. Обратите внимание, что моя - это просто компиляция или краткое резюме других ответов здесь. – Jörg 29 April 2016 в 10:15
41
ответ дан Community 6 September 2018 в 08:23
поделиться
Другие вопросы по тегам:

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