目录
场景需求分析
在Web开发中常会遇到需要执行耗时操作的场景:
大数据量导出 复杂计算任务 第三方系统长时交互 文件批量处理等
当用户在前端触发任务后,如果中途希望终止执行,需要后端支持任务中断能力。
技术实现方案
核心流程图
sequenceDiagram
前端->>后端: 发起任务请求
后端->>线程池: 提交任务,获取Future
后端-->>前端: 返回任务ID
前端->>后端: 发送终止请求(携带任务ID)
后端->>Future: 执行cancel(true)
Future->>任务线程: 发送中断信号
任务线程-->>Future: 响应中断
后端-->>前端: 返回终止结果
代码实现(SpringBoot示例)
线程池配置
@Configuration
public class TaskConfig {
@Bean("taskExecutor")
public ExecutorService taskExecutor() {
return Executors.newCachedThreadPool();
}
}
任务管理服务
@Service
public class TaskService {
private final ConcurrentMap<String, Future<?>> taskMap = new ConcurrentHashMap<>();
@Autowired
@Qualifier("taskExecutor")
private ExecutorService executorService;
// 提交任务并返回任务ID
public String submitTask(String taskId, Runnable task) {
Future<?> future = executorService.submit(task);
taskMap.put(taskId, future);
return taskId;
}
// 终止指定任务
public boolean cancelTask(String taskId) {
Future<?> future = taskMap.get(taskId);
if (future != null && !future.isDone()) {
return future.cancel(true); // 发送中断信号
}
return false;
}
// 清理已完成任务
public void cleanup() {
taskMap.entrySet().removeIf(entry -> entry.getValue().isDone());
}
}
控制器实现
@RestController
@RequestMapping("/api/task")
public class TaskController {
@Autowired
private TaskService taskService;
private static final AtomicLong taskIdCounter = new AtomicLong();
@PostMapping("/start")
public ResponseEntity<String> startTask() {
String taskId = "TASK-" + taskIdCounter.incrementAndGet();
taskService.submitTask(taskId, () -> {
//业务处理
});
return ResponseEntity.ok(taskId);
}
@PostMapping("/cancel/{taskId}")
public ResponseEntity<String> cancelTask(@PathVariable String taskId) {
boolean success = taskService.cancelTask(taskId);
return success ?
ResponseEntity.ok("任务已终止") :
ResponseEntity.status(404).body("任务不存在");
}
}
中断响应机制
注意: Future.cancel()这个方法只会发送中止信号,并不会直接中止线程,需要在业务代码主动检查线程的中止状态,并做对应的中止的业务处理
1、协作式中断:Java 中断机制是协作式的,需主动检查状态。
if (Thread.currentThread().isInterrupted()) {
//检测到已被中止
//执行对应的业务处理break、return等
}
2、状态不可逆:一旦线程被中断,isInterrupted()
会持续返回 true
,除非调用 Thread.interrupted()
清除状态。
3、资源释放:在终止逻辑中需确保释放锁、关闭连接等操作。
4、Future.cancel()原理
future.cancel(true):发送中断信号
future.cancel(false):仅取消未开始任务 返回true表示成功发送中断
总结
通过合理使用Future和线程池,可以实现: 及时响应前端终止请求 有效释放服务器资源 避免无效计算
实际开发中需要特别注意对中断信号的正确处理,建议结合具体业务场景进行异常处理和资源清理的增强。