我正在尝试编写一个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/

10-10 12:34