停止已经 运行 的线程
Stop thread that's already running
我有两个 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);
}
}
}
您的 运行 线程必须对中断信号做出反应
Thread.currentThread().isInterrupted()
否则发送中断信号无效
在这里你可以找到一个很好的解释:
Difference between shutdown and shutdownNow of Executor Service
简短回答:您无法停止不合作的 运行 线程。线程有一个已弃用的 destroy()
方法,但这会导致您的 VM 处于 "bad" 状态。
清理线程的唯一可能是中断它。但是检查中断是线程本身的任务。
所以你的 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();
的调用只会设置executorService中当前运行所有线程的interrupted
标志位。要真正中断线程,线程必须自己检查是否设置了 interrupted
标志,然后抛出一个 InterruptedException
我有两个 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);
}
}
}
您的 运行 线程必须对中断信号做出反应
Thread.currentThread().isInterrupted()
否则发送中断信号无效
在这里你可以找到一个很好的解释: Difference between shutdown and shutdownNow of Executor Service
简短回答:您无法停止不合作的 运行 线程。线程有一个已弃用的 destroy()
方法,但这会导致您的 VM 处于 "bad" 状态。
清理线程的唯一可能是中断它。但是检查中断是线程本身的任务。
所以你的 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();
的调用只会设置executorService中当前运行所有线程的interrupted
标志位。要真正中断线程,线程必须自己检查是否设置了 interrupted
标志,然后抛出一个 InterruptedException