Kaynağa Gözat

java21优化

skyline 3 ay önce
ebeveyn
işleme
e2eb70bb0e

+ 0 - 1
admin/src/main/java/com/kym/admin/AdminApplication.java

@@ -5,7 +5,6 @@ import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.FilterType;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.stereotype.Controller;

+ 9 - 11
admin/src/main/java/com/kym/admin/config/AsyncConfig.java

@@ -2,25 +2,23 @@ package com.kym.admin.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
 
 import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.Executors;
 
 
 @Configuration
+@EnableAsync  // 启用异步支持
 public class AsyncConfig {
 
+    /**
+     * Java 21 虚拟线程异步执行器
+     * 替代传统的ThreadPoolTaskExecutor,提供更好的并发性能
+     */
     @Bean("AsyncExecutor")
     public Executor customAsyncExecutor() {
-        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-        executor.setCorePoolSize(3);
-        executor.setMaxPoolSize(20);
-        executor.setQueueCapacity(1<<10);
-        executor.setKeepAliveSeconds(60);
-        executor.setThreadNamePrefix("async-exec-");
-        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
-        executor.initialize();
-        return executor;
+        // 使用虚拟线程池,每个任务都会获得一个轻量级的虚拟线程
+        return Executors.newVirtualThreadPerTaskExecutor();
     }
 }

+ 4 - 20
common/src/main/java/com/kym/common/utils/CommUtil.java

@@ -75,29 +75,13 @@ public class CommUtil {
     }
 
     /**
-     * privatmitive
      * 判断一个对象是否是基础数据类型或String
+     * 使用Java 21 instanceof pattern matching优化
      */
     public static boolean isBasicType(Object obj) {
-        if (obj instanceof String) {
-            return true;
-        } else if (obj instanceof Integer) {
-            return true;
-        } else if (obj instanceof Short) {
-            return true;
-        } else if (obj instanceof Float) {
-            return true;
-        } else if (obj instanceof Double) {
-            return true;
-        } else if (obj instanceof Byte) {
-            return true;
-        } else if (obj instanceof Boolean) {
-            return true;
-        } else if (obj instanceof Long) {
-            return true;
-        } else {
-            return obj instanceof Character;
-        }
+        return obj instanceof String || obj instanceof Integer || obj instanceof Short ||
+               obj instanceof Float || obj instanceof Double || obj instanceof Byte ||
+               obj instanceof Boolean || obj instanceof Long || obj instanceof Character;
     }
 
     public static boolean isNotEmptyAndNull(Object value) {

+ 26 - 3
miniapp/src/main/java/com/kym/miniapp/jobs/StartChargeDelayJob.java

@@ -10,6 +10,7 @@ import com.kym.service.jobs.DelayService;
 import com.kym.service.jobs.DelayedItem;
 import com.kym.service.miniapp.ChargeOrderService;
 import com.kym.service.miniapp.ChargeService;
+import jakarta.annotation.PreDestroy;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
@@ -23,6 +24,9 @@ import java.util.ArrayList;
 import java.util.concurrent.DelayQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @author skyline
@@ -44,9 +48,10 @@ public class StartChargeDelayJob implements DelayService<DelayChargeOrder> {
 
     private final static int MAX_THREAD_COUNT = 5;
     /**
-     * 线程池
+     * Java 21 虚拟线程池
+     * 替代传统的ThreadPoolExecutor,提供更好的I/O密集型任务性能
      */
-    private final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREAD_COUNT);
+    private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
 
     /**
      * 重试列表
@@ -165,4 +170,22 @@ public class StartChargeDelayJob implements DelayService<DelayChargeOrder> {
         }
         return START_DELAY_QUEUE.removeIf(queue -> queue.data.getStartChargeSeq().equals(startChargeSeq));
     }
-}
+
+    @PreDestroy
+    public void destroy() {
+        log.info("正在关闭启动充电延迟任务线程池...");
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+        }
+        log.info("启动充电延迟任务线程池已关闭");
+        // 清理队列
+        START_DELAY_QUEUE.clear();
+        // 清理重试列表
+        retryList.clear();
+    }
+}

+ 58 - 37
miniapp/src/main/java/com/kym/miniapp/jobs/StopChargeDelayJob.java

@@ -9,6 +9,7 @@ import com.kym.service.jobs.DelayService;
 import com.kym.service.jobs.DelayedItem;
 import com.kym.service.miniapp.ChargeOrderService;
 import com.kym.service.miniapp.ChargeService;
+import jakarta.annotation.PreDestroy;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
@@ -20,6 +21,9 @@ import org.springframework.stereotype.Component;
 import java.util.concurrent.DelayQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @author skyline
@@ -42,7 +46,12 @@ public class StopChargeDelayJob implements DelayService<DelayChargeOrder> {
     /**
      * 线程池
      */
-    private final ExecutorService executor = Executors.newFixedThreadPool(1);
+    private final static int MAX_THREAD_COUNT = 3;
+    /**
+     * Java 21 虚拟线程池
+     * 替代传统的ThreadPoolExecutor,提供更好的I/O密集型任务性能
+     */
+    private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
 
     public StopChargeDelayJob(ChargeOrderService chargeOrderService, ChargeService chargeService) {
         this.chargeOrderService = chargeOrderService;
@@ -78,48 +87,44 @@ public class StopChargeDelayJob implements DelayService<DelayChargeOrder> {
     }
 
     private void processDelayedOrders() {
-        while (true) {
+        // 启动线程池中的所有线程处理延迟队列
+        for (int i = 0; i < MAX_THREAD_COUNT; i++) {
             executor.execute(() -> {
                 ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> null); // 初始化为空值,避免使用new ThreadLocal()
                 log.info("预约停止充电处理线程:{}", Thread.currentThread().getName());
-                DelayedItem<DelayChargeOrder> delayedItem;
-
-                try {
-                    // 线程休眠300ms
-                    Thread.sleep(300);
-                    delayedItem = STOP_DELAY_QUEUE.take();
-                    // 停止充电
-                    var order = delayedItem.data;
-                    threadLocal.set(order.getStartChargeSeq());
-                    // 查询该设备最新订单是否是当前预约订单,是则按计划停止
-                    var currentChargeOrder = chargeOrderService.lambdaQuery().eq(ChargeOrder::getConnectorId, order.getConnectorId()).orderByDesc(ChargeOrder::getCreateTime).list().get(0);
-                    if (currentChargeOrder.getStartChargeSeq().equals(order.getStartChargeSeq())) {
-                        chargeService.queryStopCharge(order.getUserId(), order.getConnectorId());
-                        log.info("预约充电停止成功:用户:{},订单号:{},预约停止时间:{}", order.getUserId(), order.getStartChargeSeq(), order.getEndTime());
-
-                    } else {
-                        log.error("预约充电停止异常:订单不匹配:原订单:{},当前设备最新订单:{}", order.getStartChargeSeq(), currentChargeOrder.getStartChargeSeq());
-                        throw new BusinessException("预约充电停止异常");
+                while (true) {
+                    DelayedItem<DelayChargeOrder> delayedItem = null;
+                    try {
+                        // 阻塞等待延迟队列中的任务
+                        delayedItem = STOP_DELAY_QUEUE.take();
+                        log.info("出队预约停止充电订单:{}, 队列剩余:{}", delayedItem.data.getStartChargeSeq(), STOP_DELAY_QUEUE.size());
+                        // 停止充电
+                        var order = delayedItem.data;
+                        threadLocal.set(order.getStartChargeSeq());
+                        // 查询该设备最新订单是否是当前预约订单,是则按计划停止
+                        var currentChargeOrder = chargeOrderService.lambdaQuery().eq(ChargeOrder::getConnectorId, order.getConnectorId()).orderByDesc(ChargeOrder::getCreateTime).list().get(0);
+                        if (currentChargeOrder.getStartChargeSeq().equals(order.getStartChargeSeq())) {
+                            chargeService.queryStopCharge(order.getUserId(), order.getConnectorId());
+                            log.info("预约充电停止成功:用户:{}, 订单号:{}, 预约停止时间:{}", order.getUserId(), order.getStartChargeSeq(), order.getEndTime());
+
+                        } else {
+                            log.error("预约充电停止异常:订单不匹配:原订单:{}, 当前设备最新订单:{}", order.getStartChargeSeq(), currentChargeOrder.getStartChargeSeq());
+                            throw new BusinessException("预约充电停止异常");
+                        }
+
+                    } catch (Exception e) {
+                        if (e instanceof InterruptedException) {
+                            log.error("预约停止充电队列take异常", e);
+                            // 线程被中断,退出循环
+                            break;
+                        } else {
+                            log.info("预约停止充电失败,订单号:{}", threadLocal.get(), e);
+                        }
+                    } finally {
+                        threadLocal.remove();
                     }
-
-                } catch (Exception e) {
-                    if (e instanceof InterruptedException) {
-                        log.error("预约停止充电队列take异常", e);
-                    } else {
-                        log.info("预约停止充电失败,订单号:{}", threadLocal.get(), e);
-                    }
-                } finally {
-                    threadLocal.remove();
                 }
             });
-            if (!executor.isTerminated()) {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    log.error("Delay queue processing interrupted.", e);
-                    return;
-                }
-            }
         }
     }
 
@@ -141,4 +146,20 @@ public class StopChargeDelayJob implements DelayService<DelayChargeOrder> {
         }
         return STOP_DELAY_QUEUE.removeIf(queue -> queue.data.getStartChargeSeq().equals(startChargeSeq));
     }
+
+    @PreDestroy
+    public void destroy() {
+        log.info("正在关闭停止充电延迟任务线程池...");
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+        }
+        log.info("停止充电延迟任务线程池已关闭");
+        // 清理队列
+        STOP_DELAY_QUEUE.clear();
+    }
 }

+ 3 - 1
service/src/main/java/com/kym/service/admin/impl/StationServiceImpl.java

@@ -249,7 +249,9 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
         // 查询正在进行中的活动和各站点正在进行中的活动 (限充值优惠和优惠券领取活动) todo 性能待优化
         var rechargeRightsActivityList = activityService.lambdaQuery().eq(Activity::getStatus, Activity.STATUS_进行中).eq(Activity::getDiscountType, Activity.DISCOUNT_TYPE_服务费折扣权益).list();
         var couponActivityList = activityService.getAvailableCouponActivities();
-        var activityList = Stream.concat(rechargeRightsActivityList.stream(), couponActivityList.stream()).toList();
+        // Java 21: 使用ArrayList替代Stream.concat提高可读性
+        var activityList = new ArrayList<Activity>(rechargeRightsActivityList);
+        activityList.addAll(couponActivityList);
 
         if (CommUtil.isNotEmptyAndNull(activityList)) {
             var station2ActivityListMap = activityStationService.lambdaQuery().eq(ActivityStation::getStatus, Activity.STATUS_进行中).list()