我正在尝试编写一个API,以使用Java executorService和Future停止多个线程。
下面是我的代码:
@RestController
@RequestMapping("/work")
public class WorkController {
final WorkService service;
private List<Future<?>> future_list;
public WorkController(WorkService service) {
this.service = service;
this.future_list = null;
}
@RequestMapping(value="/start",
method=RequestMethod.POST,
consumes="application/json")
public String startWorks(@RequestBody List<Long> workIds) throws IOException {
// create runnables based on work ids
int work_number = workIds.size();
Collection<Runnable> worker_list= new ArrayList<>();
for (int i = 0; i < work_number; i++) {
Runnable worker = service.createWorkRunnable(workIds.get(i));
worker_list.add(worker);
}
// 4 thread pool
ExecutorService executor;
executor = Executors.newFixedThreadPool(4);
for (Runnable worker : worker_list) {
Future<?> future = executor.submit(worker);
future_list.add(future);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
return "Finished all threads";
}
@RequestMapping(value="/stop",
method=RequestMethod.POST)
public String stopWorks() {
for (Future<?> f : future_list) {
Boolean paused = f.cancel(true);
}
return "Stoped";
}
}
当我在运行可运行对象时调用stopWorks时,我得到
[ERROR] 2018-08-21 06:46:05.275 [http-nio-8090-exec-5] [dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Re
quest processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
似乎未分配未来。我在正确的轨道上尝试在多个线程上中断吗?如果是这样,我做错了什么?谢谢
最佳答案
主要问题是您没有在构造函数中初始化future_list
。此外,最好注入ExecutorService
。我对代码进行了一些重新设计,以使用其他最佳实践:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@RestController
@RequestMapping("/work")
public class WorkController {
private final WorkService service;
private final ExecutorService executor;
private List<Future<?>> futureList;
public WorkController(WorkService service, ExecutorService executor) {
this.service = service;
this.executor = executor;
this.futureList = new ArrayList<>();
}
@PostMapping(value = "/start", consumes = "application/json")
public String startWorks(@RequestBody List<Long> workIds) {
// create runnables based on work ids
Collection<Runnable> workerList = new ArrayList<>();
for (Long workId : workIds) {
Runnable worker = service.createWorkRunnable(workId);
workerList.add(worker);
}
for (Runnable worker : workerList) {
Future<?> future = executor.submit(worker);
futureList.add(future);
}
return "Finished all threads";
}
@PostMapping("/stop")
public String stopWorks() {
for (Future<?> f : futureList) {
f.cancel(true);
}
return "Stopped";
}
}
要使用
ExecutorService
进行注入,请创建一个如下所示的bean:@Bean
public ExecutorService executorService() {
return Executors.newFixedThreadPool(4);
}
请注意,即使使用此代码,仍然存在问题:
futureList
永远不会被清除,因此它将无限增长。正确处理此问题似乎并不容易,因为涉及多个线程(startWorks
可以多次调用,stopWorks
也可以多次调用)如果已经有工作繁忙,是否应该允许多次呼叫
startWorks
?关于java - 将来取消不适用于executorService的多个线程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51943507/