В Java есть два способа создания потоков, т.е. реализация интерфейса Runnable и расширение класса Thread. В этом руководстве по параллелизму Java мы выявим различия между обоими способами, т.е. расширение потока против реализации runnable.
В общем, пока у нас нет особой причины, всегда рекомендуется реализовывать интерфейс Runnable для создания новых потоков. Таким образом, дочерний класс может свободно расширять другой класс, если это необходимо.
Расширять класс Thread следует только в том случае, если мы хотим переопределить или расширить поведение самого класса Thread, и делать это вообще не рекомендуется.
1. Класс потока
Класс Thread представляет поток выполнения в программе Java. Мы расширяем класс Thread в дочернем классе и переопределяем метод run().
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}}
Чтобы запустить поток, мы вызываем его метод start().
MyThread thread = new MyThread();thread.start();
Класс Thread сам реализует интерфейс Runnable.
2. Рабочее окружение
Класс должен реализовать интерфейс Runnable, если экземпляры предназначены для выполнения потоком. Код для выполнения записывается в методе run().
public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}}
Чтобы запустить исполняемый код, мы создаем новый объект Thread и передаем исполняемый как аргумент конструктора. После этого мы можем использовать метод Thread.start() для запуска исполняемого кода.
MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();
3. Разница между Runnable и Thread
Было много споров о том, какой способ лучше. Я тоже пытался это выяснить, и ниже я изложил свои выводы.
Особенность | Запускаемый | Нить |
---|---|---|
Выполнение | Это интерфейс | Это класс |
Наследование | Дочерний класс может расширять другой класс. | Дочерний класс не может расширять другой класс. |
Возможность повторного использования кода | Один экземпляр может использоваться несколькими потоками | Каждому потоку нужен новый экземпляр |
Совместное использование ресурсов | Позволяет совместно использовать ресурсы между несколькими потоками | Труднее делиться ресурсами |
Накладные расходы памяти | Снижение затрат памяти, поскольку для потока не создается отдельный объект | Более высокие накладные расходы памяти, поскольку каждый объект потока имеет свою собственную память |
Реализация Runnable делает ваш класс более гибким. Если вы расширяете Thread, то действие, которое вы делаете, всегда будет в потоке. Однако, если вы реализуете Runnable, это не обязательно. Вы можете запустить его в потоке, передать его какой-либо службе-исполнителю или просто передать его как задачу в однопоточном приложении.
4. Заключение
Реализация Runnable — предпочтительный способ сделать это. Здесь вы не специализируете и не изменяете поведение потока. Вы просто даете потоку что-то для запуска. Это значит, что композиция — лучший способ.
Вот и все о различиях между интерфейсом Runnable и классом Thread в Java. Если вы знаете что-то еще, пожалуйста, напишите об этом в комментариях, и я включу это в содержание поста.