Почему внедрение Runnable лучше, чем расширение класса Thread?
Внедрение Runnable и расширение потока
Ответ 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 нет объектов без накладных расходов, а создание как можно меньшего количества объектов очень важно для высокопроизводительных приложений. Объекты - величайшая вещь, но ненужные объекты не...