Java - Создание потока

Здравствуйте, будущие маги Java! Сегодня мы окунемся в захватывающий мир Java-потоков. Не волнуйтесь, если вы новички в программировании; я буду вести вас по этому пути шаг за шагом, как я делал это для countless студентов на протяжении многих лет моей преподавательской деятельности. Так что возьмите любимый напиток, устройтесь поудобнее, и давайте вместе отправимся в это приключение с потоками!

Java - Creating a Thread

Что такое поток?

Прежде чем мы перейдем к созданию потоков, давайте поймем, что же такое поток на самом деле. Представьте, что вы находитесь на кухне, готовя美味的 обед. Вы нарезаете овощи, помешиваете соус и проверяете духовку одновременно. Каждая из этих задач похожа на поток в компьютерной программе - это отдельные задачи, которые могут выполняться параллельно.

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

Почему использовать потоки?

Вы можете задаваться вопросом: "Зачем мне заморачиваться с потоками?" Давайте расскажу вам一个小ую историю. Годы назад я разрабатывал простое приложение для обработки изображений для fotograf俱乐部. Приложение работало нормально для маленьких изображений, но когда пользователи пытались обработать большие изображения с высоким разрешением, оно зависало. В чем была проблема? Все выполнялось на одном потоке! Implementing многопоточность, мы смогли обрабатывать изображения в фоновом режиме, оставляя интерфейс пользователя отзывчивым. Члены клуба были в восторге, и я выучил ценный урок о силе потоков.

Создание потока в Java

В Java есть два основных способа создания потока:

  1. Реализация интерфейса Runnable
  2. Расширение класса Thread

Давайте рассмотрим оба метода на примерах!

Метод 1: Реализация интерфейса Runnable

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

Вот простой пример:

public class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Thread using Runnable: " + i);
try {
Thread.sleep(1000); // Пауза на 1 секунду
} catch (InterruptedException e) {
System.out.println("Thread interrupted.");
}
}
}

public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

// Основной поток
for (int i = 1; i <= 5; i++) {
System.out.println("Main Thread: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
}
}
}

Давайте разберем это:

  1. Мы создаем класс MyRunnable, который реализует интерфейс Runnable.
  2. Мы переопределяем метод run(), который определяет, что будет делать поток при его запуске.
  3. В методе main мы создаем экземпляр MyRunnable и передаем его новому объекту Thread.
  4. Мы вызываем start() на потоке, чтобы начать его выполнение.
  5. Основной поток также выводит числа, демонстрируя, как оба потока работают параллельно.

Когда вы запустите эту программу, вы увидите, что числа из обоих потоков чередуются, показывая, что они выполняются одновременно!

Метод 2: Расширение класса Thread

Этот метод involves создание подкласса Thread и переопределение его метода run(). Вот пример:

public class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Thread extending Thread class: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread interrupted.");
}
}
}

public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();

// Основной поток
for (int i = 1; i <= 5; i++) {
System.out.println("Main Thread: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
}
}
}

Основные различия здесь:

  1. Наш класс MyThread extends Thread вместо реализации Runnable.
  2. Мы можем напрямую вызвать start() на объекте MyThread, не создавая отдельный объект Thread.

Сравнение двух методов

Оба метода достигают одного и того же результата, но есть некоторые соображения:

Feature Runnable Interface Extending Thread Class
Гибкость Можно расширять другие классы Нельзя расширять другие классы (Java не поддерживает множественное наследование)
Разделение интересов Разделяет задачу и поток Комбинирует задачу и поток в одном классе
Репозитарность Более повторяем Меньше повторяем
Эффективность ресурсов Более эффективный (можно использовать с пулами потоков) Меньше эффективный

В большинстве случаев реализация Runnable считается更好的 практикой, так как она предлагает больше гибкости и лучше aligns с принципами объектно-ориентированного дизайна.

Заключение

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

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

Credits: Image by storyset