在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;
}
@Override
public void run() {
log.info("Task " + taskId + " is running on " + Thread.currentThread().getName());
orderProcessor.processOrder(orderNumber);
log.info("Task " + taskId + " completed.");
}
}
运行结果:
注意事项
如果使用数据库,需要考虑并发控制和事务管理。
如果使用文件锁,需要考虑文件系统的可靠性和性能。
如果使用本地缓存,需要考虑缓存的过期时间和集群环境下的同步问题。