未来取消不与多个线程的 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