Остановить поток, который уже работает - PullRequest
0 голосов
/ 13 сентября 2018

У меня есть два API: один запускает поток, а другой останавливает поток.Я успешно могу запустить поток, вызвав /start API, но не могу остановить уже запущенный поток, вызвав /stop API.Похоже, Executor#stop() ничего не делает.

Мой RestController:

@Autowired
private Executor executor;

@RequestMapping(path = "/start", method = GET)
public ResponseEntity<HttpStatus> startLongTask() {
    executor.start();
    return ResponseEntity.ok(HttpStatus.OK);
}

@RequestMapping(path = "/stop", method = GET)
public ResponseEntity<HttpStatus> stopLongTask() {
    executor.stop();
    return ResponseEntity.ok(HttpStatus.OK);
}

Мой Executor:

@Component
public class Executor {

    @Value("${threads.number}")
    private int threadsNumber;

    private ExecutorService executorService;

    @Autowired
    private OtherService otherService;

    @PostConstruct
    private void init() {
        executorService = Executors.newFixedThreadPool(threadsNumber);
        executorService = Executors.newScheduledThreadPool(threadsNumber);
    }

    /**
     * Start.
     */
    public void start() {
        executorService.submit(() -> otherService.methodImExecuting());
    }

    /**
     * Stop.
     */
    @PreDestroy
    publicvoid stop() {
        executorService.shutdownNow();
        try {
            if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
        }
    }
}

Вот methodImExecuting:

@Component
public class OtherService {

    public void methodImExecuting() {
        List<SomeObject> dataList = repository.getDataThatNeedsToBeFilled();
        for (SomeObject someObject : dataList) {
            gatewayService.sendDataToOtherResourceViaHttp(someObject);
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Краткий ответ: Вы не можете остановить работающий поток, который не взаимодействует. Существует устаревший метод destroy() для потоков, но это приведет к «плохому» состоянию вашей виртуальной машины.

Единственная возможность завершить очистку потока - это прервать его. Но проверить прерывание - задача самого потока.

Так что ваша methodImExcecuting должна выглядеть так:

void methodImExecuting() throws InterruptedException {
    // it depends on your implementation, I assume here that you iterate 
    // over a collection for example
    int loopCount = 0;
    for (Foo foo : foos) {
        ++loopCount;
        if (loopCount % 100 == 0) {
            if (Thread.interrupted())
                throw new InterruptedException();
        }
        ...
    }

От вашей реализации зависит, как часто вам придется смотреть, прерывается ли ваш поток. Но это факт, что вызов executorService.shutdownNow(); установит флаг interrupted только для всех потоков, запущенных в данный момент в executorService. Чтобы действительно прервать поток, поток должен сам проверить, установлен ли флаг interrupted, а затем выбросить InterruptedException

.
0 голосов
/ 13 сентября 2018

Ваши работающие потоки должны реагировать на сигнал прерывания

Thread.currentThread().isInterrupted()

В противном случае отправка сигнала прерывания не имеет никакого эффекта.

Здесь вы можете найти хорошее объяснение: Разница между выключением и выключением Сейчас Службы Исполнителя

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...