Задача с собеседования на Java программиста: Поток с функциями остановки, приостановки и возобновления

FAANG Master
2 min readJun 1, 2023

--

Напишите поток, который можно приостановить, продолжить/возобновить его выполнение и остановить.

Это вопрос на знание нескольких фактов:

  1. Как в Java создать поток
  2. Знание того факта, что Thread.stop(), Thread.suspend() и Thread.resume() не безопасны и deprecated. Их нельзя использовать.
  3. Знание wait-notify механизма в Java
  4. Знание volatile и/или synchronized в Java
  5. Как работает interrupt()

В Java есть встроенные методы Thread.stop(), Thread.suspend() и Thread.resume() методы у класса Thread. И новичку в многопоточности может показаться, что нужно, просто, их и использовать для этих целей. Но если вы так ответите, это будет красным флагом для вас. Интервьюер поймет, что вы не знаете этой темы совсем.

Эти методы в Java deprecated, т.к. они не безопасны. Почему это так можно почитать в официальной документации тут: https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Кратко:

Thread.stop() — бросает Error: ThreadDeath, это приводит к тому, что поток отпускает все мониторы(локи), которые держал. Если какие-то объекты были защищены этими мониторами, то они могут оказаться в промежуточном/неконсистентном состоянии. При этом другие потоки, не будут знать, что произошла остановка потока при помощи Thread.stop() и некоторые объекты могут быть в промежуточном состоянии. Это приведет к неправильной работе приложения.

Thread.suspend() — заставляет поток перейти в режим ожидания, но если поток держал какие-то мониторы(локи), то он продолжит их держать. Это может привести к dead-lock. Например, если второй поток, который должен разбудить первый тоже должен вначале получить лок на тот же объект. Они будут вечно друг друга ждать.

Как же правильно остановить поток?

Использовать метод interrupt() + в методе run потока проверять флаг isInterruped() и реагировать на InterruptedException, который могут бросить блокирующие операции.

Как можно приостановить и возобновить выполнение потока?

Например, при помощи wait-notify механизма. Смотри мои статьи про методы Object и задачу на wait-notify: Ping-Pong.

В run добавим:

synchronized (this) {
while (isSuspended) {
wait();
}
}

И чтобы приостановить:

isSuspended = true;

Важный момент: isSuspended должна меняться или в synchronized блоке или быть объявленной как volatile для обеспечения visibility. Смотрите более подробно про volatile: https://www.baeldung.com/java-volatile

volatile boolean isSuspended

И чтобы возобновить работу потока:

public synchronized void customResume() {
this.isSuspended = false;
notifyAll();
}

Итого, все вместе:

public class Main {
public static void main(String[] args) throws InterruptedException {
ResumableThread t = new ResumableThread();
t.start();
Thread.sleep(10000);
t.customSuspend();
Thread.sleep(10000);
t.customResume();
Thread.sleep(10000);
t.customTerminate();
}
}

class ResumableThread extends Thread {
private volatile boolean isSuspended;

public synchronized void customResume() {
this.isSuspended = false;
notifyAll();
}

public void customSuspend() {
this.isSuspended = true;
}

public void customTerminate() {
interrupt();
}

public void run() {
try {
while (!isInterrupted()) {
doWork();
synchronized (this) {
while (isSuspended) {
System.out.println("Going to sleep");
wait();
}
}
}
System.out.println("Interrupted");
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}

private void doWork() throws InterruptedException {
// Что-то очень важное выполняем
System.out.println("Doing some work");
Thread.sleep(1000);
}
}

--

--

FAANG Master
FAANG Master

Written by FAANG Master

Статьи теперь пишу на https://dev.to/faangmaster, Мой телеграм канал: https://t.me/faangmaster, Мой youtube: https://www.youtube.com/@FAANGMaster

No responses yet