Потоки — это инструмент, который позволяет выполнять части программы одновременно.
Потоки представлены классом Thread (англ. «нить»), поскольку по-английски поток выполнения называется thread of execution.
Рассмотрим пример программы с двумя потоками: thread1 и thread2. Каждый из этих потоков десять раз выводит в консоль по одному символу. Один поток будет печатать o, а второй — X. Код при этом будет выглядеть так:
public class TwoThreads {
private static final int PRINT_COUNT = 10;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < PRINT_COUNT; i++) {
System.out.print("o");
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < PRINT_COUNT; i++) {
System.out.print("X");
}
});
thread1.start();
thread2.start();
}
}
Разберёмся, как работает эта программа. В начале метода main() с помощью класса Thread создаются потоки. Для этого в конструктор класса Thread передаются объекты типа Runnable (англ. «запускаемый»). В нашем примере такие объекты создаются с помощью лямбда-выражений вида () -> { /* действия */ }. Именно в них описано, чем будет заниматься поток и какие действия он будет выполнять.
После создания потоки запускаются с помощью метода thread.start(). Метод start() запускает поток, но не ждёт, пока тот завершится. Он будто бы говорит потоку: «Иди работай». И считает на этом свою задачу выполненной. Таким образом, строка thread2.start() выполнится сразу же после строки thread1.start().
Альтернативные способы создания Runnable
В примере выше объекты типа Runnable создаются с помощью лямбда-выражений и сразу же передаются в конструктор Thread.
Выглядит это так.
Thread thread = new Thread(() -> {
/* код, который выполнится в отдельном потоке */ });
Но есть и другие варианты.
Например, можно явно создавать переменную типа Runnable.
Runnable runnable = () -> {
/* код, который выполнится в отдельном потоке */ };
Thread thread = new Thread(runnable);