在Java中处理长时间的任务并且需要避免重复处理同一张单据的情况下,在不使用Redis或其他外部存储服务情况下。
方法一:使用数据库表 表记录记录状态
方法二:使用文件系统 创建和删除文件记录状态
方法三:使用本地缓存
import java.util.concurrent.ConcurrentHashMap;public class OrderStatusService {private final ConcurrentHashMap<String, Boolean> processingOrders = new ConcurrentHashMap<>();public boolean isOrderBeingProcessed(String orderNumber) {return processingOrders.getOrDefault(orderNumber, false);}public void markOrderAsProcessing(String orderNumber) {processingOrders.put(orderNumber, true);}public void markOrderAsCompleted(String orderNumber) {processingOrders.remove(orderNumber);}
}
@Sl4j
public class OrderProcessor {private final OrderStatusService orderStatusService;public OrderProcessor(OrderStatusService orderStatusService) {this.orderStatusService = orderStatusService;}public void processOrder(String orderNumber) {log.info("Order " + orderNumber + " startProcess.");if (!orderStatusService.isOrderBeingProcessed(orderNumber)) {try {orderStatusService.markOrderAsProcessing(orderNumber);// 处理单据的业务逻辑handleBusinessLogic(orderNumber);orderStatusService.markOrderAsCompleted(orderNumber);} catch (Exception e) {// 处理异常情况e.printStackTrace();}}else{log.error("Order " + orderNumber + " repeat.");}}private void handleBusinessLogic(String orderNumber) {// 模拟处理逻辑try {Thread.sleep(60000); // 模拟长时间处理} catch (InterruptedException e) {e.printStackTrace();}log.info("Order " + orderNumber + " processed.");}}
模拟测试:
public static void main(String[] args) throws Exception{OrderStatusService orderStatusService=new OrderStatusService();OrderProcessor orderProcessor=new OrderProcessor(orderStatusService);
// orderProcessor.processOrder("1111");
// orderProcessor.processOrder("2222");
// orderProcessor.processOrder("1111");ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池executor.submit(new TaskRunner(1,"1111",orderProcessor));Thread.sleep(200);executor.submit(new TaskRunner(2,"2222",orderProcessor));Thread.sleep(200);executor.submit(new TaskRunner(3,"1111",orderProcessor));executor.shutdown(); // 关闭线程池}static class TaskRunner implements Runnable {private final int taskId;private final String orderNumber;private final OrderProcessor orderProcessor;public TaskRunner(int taskId,String orderNumber,OrderProcessor orderProcessor) {this.taskId = taskId;this.orderNumber = orderNumber;this.orderProcessor = orderProcessor;}@Overridepublic void run() {log.info("Task " + taskId + " is running on " + Thread.currentThread().getName());orderProcessor.processOrder(orderNumber);log.info("Task " + taskId + " completed.");}}
运行结果:
注意事项
如果使用数据库,需要考虑并发控制和事务管理。
如果使用文件锁,需要考虑文件系统的可靠性和性能。
如果使用本地缓存,需要考虑缓存的过期时间和集群环境下的同步问题。