Внедрение Runnable и расширение потока

Почему внедрение Runnable лучше, чем расширение класса Thread?

Ответ 1

Таким образом вы отмените вычисление (того, что) из исполнения (, когда и/или , как strong > ).

С Runnable или Callable вы можете, например, отправить много работ/вычислений в Executor, которые позаботятся о планировании материалов. Вот выдержка ExecutorService:

pool = Executors.newFixedThreadPool(poolSize);
...
pool.execute(new Handler(serverSocket.accept()));
...
class Handler implements Runnable {
    ...
 }

Использование Runnable/Callable дает вам большую гибкость при непосредственном использовании потоков.

Ответ 2

Фактическая точка, которую нужно убрать, - это то, что инструменты ВСЕГДА предпочтительнее, чем расширения в любых сомнительных случаях.

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

Когда я впервые "понял" программирование OO, я расширял ВСЕ, но он превратил весь мой дизайн в кашу. Теперь я распространяю только те немногие вещи, которые четко и явно проходят тест "is-a", а все остальное - интерфейс...

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

Кажется, каждые три года (за последние 20 лет) я думаю, что я действительно "получаю" программирование и оглядываюсь на тупые вещи, которые я делал 3 года назад в стыде... Это был один из таких случаев (но из более близких до 7 лет назад в этот момент)

Ответ 3

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

Это согласуется со Скоттом Мейерсом, очень хорошим советом в "Более эффективном С++": Сделайте абстрактные классы нелитературными. Замените интерфейсы, и вы находитесь на месте.

Ответ 4

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

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

Ответ 5

Причины, по которым вы предпочитаете использовать Interface Runnable для расширения Тема класса:

  • меньше накладных расходов в секвенциальном контексте (источник)

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

Источник: блог - Я не совсем уверен, правильно ли это.

  • вы можете отправлять задачи по сети с помощью Runnable (нить не сериализуема, источник)
  • лучше стиль ООП
    • Очень вероятно, что у вас нет отношения "есть".
    • у вас есть возможность расширить другие классы (Java не имеет множественного наследования)

Ответ 6

Сначала ответьте на вопрос:

Если вы расширяете поток, экземпляр вашего класса (расширенный поток) всегда будет вызывать конструктор потока суперкласса. Так   MyClass myclass= new MyClass() всегда вызывает "super()" внутри конструктора MyClass, который создает поток, и, в конце концов, вы можете реализовать некоторые накладные расходы в своем классе (если вы не используете какой-либо метод потока суперкласса). Таким образом, реализация только Runnable позволяет вашему классу работать быстрее без каких-либо наследуемых служебных данных.

Кроме того, здесь есть некоторые неправильные ответы:

Теперь я распространяю лишь те немногие вещи, которые четко и явно проходят тест "is-a", а все остальное - интерфейс...

Разве вы никогда не рассматривали возможность создания объекта без какого-либо интерфейса? Потому что было бы очень неправильно реализовать интерфейс для каждого объекта!

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

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

Вывод: В java каждый экземпляр класса является объектом и расширяет объект класса (в то время как примитивы не являются... только массив примитивов типа int [] расширяет Object, и такие массивы имеют те же методы, что и любой объект, но, к сожалению, они не упоминаются в Javadoc! Ребята из Sun, вероятно, не хотели, чтобы мы их использовали).

Btw есть по крайней мере два преимущества наследования: совместное использование кода и ясный Javadoc. Потому что, если вы унаследовали от класса, вы можете увидеть все подклассы в Javadoc. Вы можете сделать это и с интерфейсом, но тогда вы не можете использовать код. Более того, вам нужно будет создать "вложенные" объекты и вызвать конструктор из двух или более объектов вместо одного, и это снова означает, что вы реализуете некоторые накладные расходы из самого объекта Суперкласса! Поскольку на Java нет объектов без накладных расходов, а создание как можно меньшего количества объектов очень важно для высокопроизводительных приложений. Объекты - величайшая вещь, но ненужные объекты не...