未来取消不与多个线程的 executorService 一起使用
Future cancel not working with executorService for multiple threads
我正在尝试编写一个 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
:
public WorkController(WorkService service) {
this.service = service;
this.future_list = null; // assign it a List instead 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
?
我正在尝试编写一个 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
:
public WorkController(WorkService service) {
this.service = service;
this.future_list = null; // assign it a List instead 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
?