凉山州住房和城乡建设厅网站js获取网站广告点击量怎么做

张小明 2025/12/29 6:12:48
凉山州住房和城乡建设厅网站,js获取网站广告点击量怎么做,网站建设金牛万达,找到网站永久域名在Java并发编程中#xff0c;线程池是控制线程生命周期、提升系统性能的核心组件#xff0c;而单例模式则是确保实例唯一、避免资源浪费的经典设计模式。将两者结合#xff0c;实现“线程池的单例模式”#xff0c;是解决“重复创建线程池导致资源耗尽”“线程池实例混乱难…在Java并发编程中线程池是控制线程生命周期、提升系统性能的核心组件而单例模式则是确保实例唯一、避免资源浪费的经典设计模式。将两者结合实现“线程池的单例模式”是解决“重复创建线程池导致资源耗尽”“线程池实例混乱难以管控”等生产问题的关键方案。但你可能会问为什么不能直接用Executors创建线程池单例模式的多种实现方式中哪种最适合线程池如何保证单例线程池的线程安全、延迟加载和高可用性一、先搞懂为什么需要“单例线程池”在讲解实现方案前我们必须先明确核心问题为什么要给线程池加单例模式直接创建线程池不行吗1.1 直接创建线程池的3个致命问题日常开发中很多人会直接通过Executors.newFixedThreadPool(10)创建线程池但这种方式在多线程环境下会引发严重问题资源耗尽风险若多个业务模块重复创建线程池会导致系统中线程数量暴增超出CPU和内存承载能力触发OutOfMemoryError或ThreadCreationException管控混乱分散的线程池无法统一配置如拒绝策略、空闲线程存活时间排查问题时难以定位线程归属运维成本极高内存泄漏未正确关闭的线程池会持有核心线程导致JVM无法正常退出长期运行会造成内存泄漏。1.2 单例模式的核心价值线程池的“唯一管控入口”单例模式的核心是“确保一个类只有一个实例并提供全局访问点”。将其应用于线程池可实现资源复用全局唯一的线程池实例避免重复创建线程减少CPU上下文切换和内存占用统一管控所有业务线程通过同一个线程池执行便于统一配置参数、监控线程状态如活跃线程数、任务队列长度避免竞态条件单例模式的线程安全实现可防止多线程并发创建线程池时的实例冲突。1.3 权威依据阿里巴巴Java开发手册的明确要求《阿里巴巴Java开发手册嵩山版》第6章“并发编程”明确规定【强制】线程池不允许使用Executors创建必须通过ThreadPoolExecutor的构造方法手动创建避免默认参数隐藏的风险如newCachedThreadPool的无界队列导致OOM【推荐】核心业务线程池应统一管理避免分散创建。这为“单例线程池”的设计提供了权威依据单例模式是实现线程池统一管理的最佳载体。二、底层逻辑线程池与单例模式的核心原理要实现“线程安全、高性能”的单例线程池必须先掌握两者的底层逻辑避免因理解偏差导致的实现缺陷。2.1 线程池的核心原理ThreadPoolExecutor的工作机制Java中的线程池核心实现是ThreadPoolExecutor其构造方法定义如下JDK 17public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnable workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)核心工作流程可概括为当提交任务时若核心线程数未达corePoolSize直接创建核心线程执行任务若核心线程已满将任务放入workQueue队列等待若队列已满且当前线程数未达maximumPoolSize创建非核心线程执行任务若队列和最大线程数均已满触发handler拒绝策略如丢弃任务、抛出异常。流程图如下2.2 单例模式的核心要求线程安全、延迟加载、高性能单例模式的实现方式有多种饿汉式、懒汉式、双重检查锁、静态内部类等但适用于线程池的单例必须满足3个核心要求线程安全多线程并发调用时不会创建多个实例延迟加载避免程序启动时就创建线程池减少初始化开销高性能避免频繁加锁影响并发效率。不同单例实现方式的对比权威结论来自《Effective Java》第3条实现方式线程安全延迟加载高性能适用场景饿汉式是否是实例初始化开销小的场景懒汉式同步方法是是否并发量极低的场景双重检查锁DCL是需volatile是是大多数并发场景静态内部类是是是无特殊依赖的场景对于线程池而言双重检查锁DCL和静态内部类是最优实现方式两者均满足线程安全、延迟加载、高性能的要求且适配线程池的初始化特性。三、实战实现3种生产级单例线程池方案结合底层逻辑和权威规范下面提供3种可直接用于生产的单例线程池实现方案所有代码基于JDK 17编写严格遵循阿里巴巴开发手册可直接编译运行。3.1 方案1静态内部类实现推荐无锁高性能静态内部类实现单例的核心原理外部类加载时静态内部类不会被加载实现延迟加载类加载过程由JVM保证线程安全无需额外加锁访问静态内部类的静态属性时JVM才会加载内部类并初始化实例性能极高。适用于无特殊配置依赖如线程池参数需动态调整的场景是最通用的推荐方案。3.1.1 完整实现代码package com.jam.demo.threadpool; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * 静态内部类实现单例线程池推荐方案 * 核心优势线程安全、延迟加载、无锁高性能 * 适用场景线程池参数固定无动态调整需求的生产环境 * author ken */ Slf4j public class StaticInnerClassThreadPool { /** * 核心线程数CPU核心数 1阿里巴巴开发手册推荐平衡CPU和IO密集型任务 */ private static final int CORE_POOL_SIZE Runtime.getRuntime().availableProcessors() 1; /** * 最大线程数CPU核心数 * 2避免线程过多导致上下文切换频繁 */ private static final int MAX_POOL_SIZE Runtime.getRuntime().availableProcessors() * 2; /** * 非核心线程空闲存活时间30秒无任务时销毁非核心线程释放资源 */ private static final long KEEP_ALIVE_TIME 30L; /** * 任务队列容量1000的有界队列避免无界队列导致OOM阿里巴巴开发手册强制要求 */ private static final BlockingQueueRunnable WORK_QUEUE new ArrayBlockingQueue(1000); /** * 线程工厂自定义线程名称便于问题排查 */ private static final ThreadFactory THREAD_FACTORY new ThreadFactory() { // 原子类保证线程编号唯一 private final AtomicInteger threadNum new AtomicInteger(1); Override public Thread newThread(Runnable r) { Thread thread new Thread(r); thread.setName(static-inner-pool-thread- threadNum.getAndIncrement()); // 捕获线程未处理的异常避免线程意外终止 thread.setUncaughtExceptionHandler((t, e) - log.error(线程[{}]执行任务异常, t.getName(), e)); return thread; } }; /** * 拒绝策略任务队列满时丢弃最老的任务并执行当前任务平衡吞吐量和任务优先级 */ private static final RejectedExecutionHandler REJECTED_HANDLER new ThreadPoolExecutor.DiscardOldestPolicy(); /** * 私有构造方法禁止外部实例化 */ private StaticInnerClassThreadPool() { // 防止通过反射破坏单例 if (!ObjectUtils.isEmpty(StaticInnerClassHolder.INSTANCE)) { throw new IllegalStateException(单例实例已存在禁止重复创建); } } /** * 静态内部类延迟加载实例 */ private static class StaticInnerClassHolder { private static final ThreadPoolExecutor INSTANCE new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, WORK_QUEUE, THREAD_FACTORY, REJECTED_HANDLER ); /** * JVM退出时关闭线程池确保资源释放 */ static { Runtime.getRuntime().addShutdownHook(new Thread(() - { log.info(JVM退出关闭静态内部类单例线程池); INSTANCE.shutdown(); try { // 等待10秒若仍有任务未执行则强制关闭 if (!INSTANCE.awaitTermination(10, TimeUnit.SECONDS)) { INSTANCE.shutdownNow(); log.warn(静态内部类线程池强制关闭可能存在未执行完的任务); } } catch (InterruptedException e) { INSTANCE.shutdownNow(); log.error(静态内部类线程池关闭过程被中断, e); } })); } } /** * 全局访问点获取单例线程池实例 * return 线程池实例 */ public static ThreadPoolExecutor getInstance() { return StaticInnerClassHolder.INSTANCE; } /** * 提交任务带返回值 * param task 任务 * param T 返回值类型 * return Future对象用于获取任务结果 */ public static T FutureT submit(CallableT task) { if (ObjectUtils.isEmpty(task)) { throw new IllegalArgumentException(提交的任务不能为空); } return getInstance().submit(task); } /** * 提交任务无返回值 * param task 任务 */ public static void execute(Runnable task) { if (ObjectUtils.isEmpty(task)) { throw new IllegalArgumentException(提交的任务不能为空); } getInstance().execute(task); } }3.1.2 关键设计细节说明线程池参数配置严格遵循阿里巴巴开发手册核心线程数和最大线程数基于CPU核心数动态计算避免硬编码使用有界队列ArrayBlockingQueue防止OOM线程工厂自定义设置线程名称便于排查问题和未捕获异常处理器避免线程静默终止关闭钩子Shutdown HookJVM退出时自动关闭线程池避免资源泄漏反射防护私有构造方法中检查实例是否已存在防止通过反射破坏单例入参校验提交任务时校验任务是否为空符合“防御性编程”规范。3.1.3 测试代码可直接运行package com.jam.demo.threadpool.test; import com.jam.demo.threadpool.StaticInnerClassThreadPool; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * 静态内部类单例线程池测试 * author ken */ Slf4j public class StaticInnerClassThreadPoolTest { Test public void testSingleInstance() { // 多线程并发获取实例验证唯一性 for (int i 0; i 10; i) { new Thread(() - { StaticInnerClassThreadPool pool1 StaticInnerClassThreadPool.getInstance(); StaticInnerClassThreadPool pool2 StaticInnerClassThreadPool.getInstance(); log.info(线程[{}]获取的两个实例是否相同{}, Thread.currentThread().getName(), pool1 pool2); }, test-thread- i).start(); } // 等待所有测试线程执行完成 try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(测试线程等待被中断, e); } } Test public void testSubmitTask() throws Exception { // 提交带返回值的任务 FutureString future StaticInnerClassThreadPool.submit(() - { TimeUnit.MILLISECONDS.sleep(500); return 任务执行成功; }); // 获取任务结果 String result future.get(); log.info(带返回值任务执行结果{}, result); // 提交无返回值的任务 StaticInnerClassThreadPool.execute(() - { try { TimeUnit.MILLISECONDS.sleep(300); log.info(无返回值任务执行完成); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(无返回值任务执行被中断, e); } }); // 等待任务执行完成 TimeUnit.SECONDS.sleep(2); } }3.1.4 测试结果说明testSingleInstance10个并发线程获取的实例均相同验证了单例的唯一性testSubmitTask任务能正常执行带返回值的任务可通过Future获取结果无返回值的任务日志正常输出验证了线程池的可用性。3.2 方案2双重检查锁DCL实现支持动态参数配置双重检查锁DCL实现单例的核心原理第一次检查未加锁快速判断实例是否存在避免频繁加锁第二次检查加锁后判断实例是否存在防止多线程并发创建volatile关键字禁止指令重排序避免“半初始化实例”问题JDK 1.5支持JDK 17完全兼容。适用于线程池参数需要动态调整如从配置文件读取的场景灵活性高于静态内部类方案。3.2.1 完整实现代码package com.jam.demo.threadpool; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * 双重检查锁DCL实现单例线程池 * 核心优势线程安全、延迟加载、支持动态参数配置 * 适用场景线程池参数需从配置文件读取或动态调整的生产环境 * author ken */ Slf4j public class DclThreadPool { /** * volatile关键字禁止指令重排序避免半初始化实例问题 */ private static volatile ThreadPoolExecutor instance; /** * 核心线程数默认值可通过配置动态覆盖 */ private static int corePoolSize Runtime.getRuntime().availableProcessors() 1; /** * 最大线程数默认值可通过配置动态覆盖 */ private static int maxPoolSize Runtime.getRuntime().availableProcessors() * 2; /** * 非核心线程空闲存活时间默认30秒 */ private static long keepAliveTime 30L; /** * 任务队列容量默认1000可通过配置动态覆盖 */ private static int queueCapacity 1000; /** * 私有构造方法禁止外部实例化 */ private DclThreadPool() { // 防止反射破坏单例 if (!ObjectUtils.isEmpty(instance)) { throw new IllegalStateException(单例实例已存在禁止重复创建); } } /** * 初始化线程池参数可在程序启动时从配置文件调用 * param corePoolSize 核心线程数 * param maxPoolSize 最大线程数 * param keepAliveTime 非核心线程存活时间 * param queueCapacity 任务队列容量 */ public static void initParams(int corePoolSize, int maxPoolSize, long keepAliveTime, int queueCapacity) { // 入参校验符合阿里巴巴开发手册参数校验优先 if (corePoolSize 0) { throw new IllegalArgumentException(核心线程数必须大于0); } if (maxPoolSize corePoolSize) { throw new IllegalArgumentException(最大线程数不能小于核心线程数); } if (keepAliveTime 0) { throw new IllegalArgumentException(存活时间不能小于0); } if (queueCapacity 0) { throw new IllegalArgumentException(队列容量必须大于0); } DclThreadPool.corePoolSize corePoolSize; DclThreadPool.maxPoolSize maxPoolSize; DclThreadPool.keepAliveTime keepAliveTime; DclThreadPool.queueCapacity queueCapacity; log.info(DCL单例线程池参数初始化完成corePoolSize{}, maxPoolSize{}, keepAliveTime{}, queueCapacity{}, corePoolSize, maxPoolSize, keepAliveTime, queueCapacity); } /** * 全局访问点双重检查锁获取单例线程池实例 * return 线程池实例 */ public static ThreadPoolExecutor getInstance() { // 第一次检查未加锁快速判断实例是否存在 if (ObjectUtils.isEmpty(instance)) { // 加锁保证并发安全 synchronized (DclThreadPool.class) { // 第二次检查防止多线程并发创建多个实例 if (ObjectUtils.isEmpty(instance)) { // 线程工厂自定义线程名称 ThreadFactory threadFactory new ThreadFactory() { private final AtomicInteger threadNum new AtomicInteger(1); Override public Thread newThread(Runnable r) { Thread thread new Thread(r); thread.setName(dcl-pool-thread- threadNum.getAndIncrement()); thread.setUncaughtExceptionHandler((t, e) - log.error(线程[{}]执行任务异常, t.getName(), e)); return thread; } }; // 任务队列有界队列 BlockingQueueRunnable workQueue new ArrayBlockingQueue(queueCapacity); // 拒绝策略抛出异常核心业务推荐及时发现问题 RejectedExecutionHandler rejectedHandler new ThreadPoolExecutor.AbortPolicy(); // 初始化线程池实例 instance new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, rejectedHandler ); // JVM退出时关闭线程池 Runtime.getRuntime().addShutdownHook(new Thread(() - { log.info(JVM退出关闭DCL单例线程池); instance.shutdown(); try { if (!instance.awaitTermination(10, TimeUnit.SECONDS)) { instance.shutdownNow(); log.warn(DCL线程池强制关闭可能存在未执行完的任务); } } catch (InterruptedException e) { instance.shutdownNow(); log.error(DCL线程池关闭过程被中断, e); } })); log.info(DCL单例线程池实例创建完成); } } } return instance; } /** * 提交任务带返回值 * param task 任务 * param T 返回值类型 * return Future对象 */ public static T FutureT submit(CallableT task) { if (ObjectUtils.isEmpty(task)) { throw new IllegalArgumentException(提交的任务不能为空); } return getInstance().submit(task); } /** * 提交任务无返回值 * param task 任务 */ public static void execute(Runnable task) { if (ObjectUtils.isEmpty(task)) { throw new IllegalArgumentException(提交的任务不能为空); } getInstance().execute(task); } }3.2.2 关键设计细节说明动态参数配置提供initParams方法可在程序启动时从配置文件如application.yml读取参数灵活性更高volatile关键字修饰instance变量禁止JVM指令重排序避免“实例已赋值但未初始化完成”的半初始化问题JDK 1.5前的bugJDK 17已完全修复但仍需显式声明以符合规范双重检查锁两次判断实例是否存在第一次无锁快速判断第二次加锁保证并发安全兼顾性能和线程安全拒绝策略选择核心业务推荐使用AbortPolicy抛出异常及时发现任务队列满的问题非核心业务可选择DiscardOldestPolicy或CallerRunsPolicy。3.2.3 测试代码含动态参数初始化package com.jam.demo.threadpool.test; import com.jam.demo.threadpool.DclThreadPool; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * DCL单例线程池测试 * author ken */ Slf4j public class DclThreadPoolTest { /** * 程序启动时初始化线程池参数模拟从配置文件读取 */ Before public void init() { DclThreadPool.initParams(5, 10, 60, 2000); } Test public void testSingleInstance() { // 多线程并发获取实例 for (int i 0; i 15; i) { new Thread(() - { DclThreadPool pool1 DclThreadPool.getInstance(); DclThreadPool pool2 DclThreadPool.getInstance(); log.info(线程[{}]获取的两个实例是否相同{}, Thread.currentThread().getName(), pool1 pool2); }, dcl-test-thread- i).start(); } try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(测试线程等待被中断, e); } } Test public void testDynamicParams() { ThreadPoolExecutor pool DclThreadPool.getInstance(); log.info(核心线程数{}, pool.getCorePoolSize()); log.info(最大线程数{}, pool.getMaximumPoolSize()); log.info(任务队列容量{}, pool.getQueue().remainingCapacity() pool.getQueue().size()); // 提交任务验证 DclThreadPool.execute(() - { try { TimeUnit.MILLISECONDS.sleep(200); log.info(动态参数配置的线程池任务执行完成); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(任务执行被中断, e); } }); FutureInteger future DclThreadPool.submit(() - { TimeUnit.MILLISECONDS.sleep(300); return 1 1; }); try { log.info(带返回值任务结果{}, future.get()); } catch (Exception e) { log.error(获取任务结果异常, e); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error(等待任务执行完成被中断, e); } } }3.2.4 测试结果说明init方法模拟程序启动时从配置文件初始化参数日志输出参数初始化完成信息testSingleInstance15个并发线程获取的实例均相同验证单例唯一性testDynamicParams输出的核心线程数、最大线程数等与初始化参数一致任务正常执行验证动态参数配置的有效性。3.3 方案3Spring Bean单例实现集成Spring生态在Spring生态中Bean默认是单例的可直接将线程池定义为Spring Bean由Spring容器管理其生命周期无需手动实现单例模式。这种方案适用于Spring Boot/Spring Cloud项目集成度高可利用Spring的配置、监控等特性。3.3.1 完整实现代码Spring Boot环境Maven依赖pom.xmldependencies !-- Spring Boot核心依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId version3.2.5/version /dependency !-- Lombok依赖Slf4j -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependency !-- Spring Boot测试依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId version3.2.5/version scopetest/scope /dependency /dependencies线程池配置类package com.jam.demo.threadpool.config; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.ObjectUtils; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * Spring Bean单例线程池配置类 * 核心优势集成Spring生态由Spring管理生命周期支持配置文件动态配置 * 适用场景Spring Boot/Spring Cloud项目 * author ken */ Configuration Slf4j public class SpringBeanThreadPoolConfig { /** * 从配置文件读取参数application.yml */ Value(${threadpool.core-pool-size:${runtime.availableProcessors}1}) private int corePoolSize; Value(${threadpool.max-pool-size:${runtime.availableProcessors}*2}) private int maxPoolSize; Value(${threadpool.keep-alive-time:30}) private long keepAliveTime; Value(${threadpool.queue-capacity:1000}) private int queueCapacity; /** * 定义线程池Bean默认单例 * return 线程池实例 */ Bean(destroyMethod shutdown) // 容器销毁时调用shutdown方法关闭线程池 public ThreadPoolExecutor springBeanThreadPool() { // 线程工厂 ThreadFactory threadFactory new ThreadFactory() { private final AtomicInteger threadNum new AtomicInteger(1); Override public Thread newThread(Runnable r) { Thread thread new Thread(r); thread.setName(spring-bean-pool-thread- threadNum.getAndIncrement()); thread.setUncaughtExceptionHandler((t, e) - log.error(线程[{}]执行任务异常, t.getName(), e)); return thread; } }; // 任务队列 BlockingQueueRunnable workQueue new ArrayBlockingQueue(queueCapacity); // 拒绝策略调用者运行非核心业务避免任务丢失 RejectedExecutionHandler rejectedHandler new ThreadPoolExecutor.CallerRunsPolicy(); // 初始化线程池 ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, rejectedHandler ); log.info(Spring Bean单例线程池初始化完成corePoolSize{}, maxPoolSize{}, keepAliveTime{}, queueCapacity{}, corePoolSize, maxPoolSize, keepAliveTime, queueCapacity); return threadPoolExecutor; } }配置文件application.yml# 线程池配置可根据环境动态调整 threadpool: core-pool-size: 6 max-pool-size: 12 keep-alive-time: 60 queue-capacity: 2000业务服务类使用线程池package com.jam.demo.threadpool.service; import com.jam.demo.threadpool.config.SpringBeanThreadPoolConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.util.concurrent.Future; /** * 业务服务类使用Spring Bean单例线程池 * author ken */ Service Slf4j public class BusinessService { /** * 注入Spring管理的单例线程池 */ Resource private SpringBeanThreadPoolConfig springBeanThreadPoolConfig; /** * 执行业务任务 * param taskId 任务ID * return 任务执行结果 */ public FutureString executeBusinessTask(String taskId) { // 入参校验 if (ObjectUtils.isEmpty(taskId)) { throw new IllegalArgumentException(任务ID不能为空); } return springBeanThreadPoolConfig.springBeanThreadPool().submit(() - { // 模拟业务逻辑执行 Thread.sleep(500); log.info(业务任务[{}]执行完成, taskId); return 任务[ taskId ]执行成功; }); } }3.3.2 关键设计细节说明Spring Bean生命周期管理通过Bean(destroyMethod shutdown)指定容器销毁时关闭线程池避免资源泄漏配置文件动态配置通过Value注解从application.yml读取参数支持多环境dev/test/prod配置集成Spring生态可结合Spring的监控如Actuator、事务管理等特性适合企业级应用依赖注入业务类通过Resource或Autowired注入线程池符合Spring的依赖倒置原则。3.3.3 测试代码package com.jam.demo.threadpool.test; import com.jam.demo.threadpool.service.BusinessService; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import java.util.concurrent.Future; /** * Spring Bean单例线程池测试 * author ken */ SpringBootTest RunWith(SpringRunner.class) Slf4j public class SpringBeanThreadPoolTest { Resource private BusinessService businessService; Test public void testSpringBeanThreadPool() throws Exception { // 多次获取线程池实例验证单例 SpringBeanThreadPoolConfig config1 businessService.getSpringBeanThreadPoolConfig(); SpringBeanThreadPoolConfig config2 businessService.getSpringBeanThreadPoolConfig(); log.info(两个Spring Bean实例是否相同{}, config1 config2); // 执行业务任务 FutureString future1 businessService.executeBusinessTask(T001); FutureString future2 businessService.executeBusinessTask(T002); log.info(任务T001执行结果{}, future1.get()); log.info(任务T002执行结果{}, future2.get()); } }3.3.4 测试结果说明两个SpringBeanThreadPoolConfig实例相同验证了Spring Bean的单例特性业务任务正常执行日志输出任务执行信息验证线程池的可用性容器销毁时线程池会自动调用shutdown方法关闭资源正常释放。四、关键对比3种方案的选型建议实现方案核心优势适用场景缺点静态内部类无锁高性能、实现简单无动态参数需求的通用场景不支持动态调整参数双重检查锁DCL支持动态参数、灵活性高需动态配置参数的场景实现稍复杂需注意volatile关键字Spring Bean集成Spring生态、配置便捷Spring Boot/Spring Cloud项目依赖Spring环境非Spring项目无法使用选型建议非Spring项目优先选择“静态内部类方案”简单、高性能若需动态参数选择“双重检查锁方案”Spring项目优先选择“Spring Bean方案”集成度高、运维便捷核心业务推荐使用“双重检查锁方案”或“Spring Bean方案”便于动态调整参数和监控非核心业务可使用“静态内部类方案”简化实现。五、避坑指南单例线程池的5个常见错误5.1 错误1使用Executors创建线程池错误示例// 错误Executors创建的线程池存在OOM风险 public static ExecutorService getInstance() { if (instance null) { synchronized (SingletonThreadPool.class) { if (instance null) { instance Executors.newFixedThreadPool(10); } } } return instance; }问题原因Executors.newFixedThreadPool使用无界队列LinkedBlockingQueue任务过多时会导致队列无限增长触发OOM。解决方案通过ThreadPoolExecutor构造方法手动创建使用有界队列。5.2 错误2DCL实现未加volatile关键字错误示例// 错误未加volatile可能出现半初始化实例 private static ThreadPoolExecutor instance; public static ThreadPoolExecutor getInstance() { if (instance null) { synchronized (DclThreadPool.class) { if (instance null) { instance new ThreadPoolExecutor(...); } } } return instance; }问题原因new ThreadPoolExecutor(...)可分解为3步1. 分配内存2. 初始化实例3. 赋值给instance。JVM可能重排序为1→3→2导致其他线程获取到“未初始化完成的实例”。解决方案用volatile修饰instance变量禁止指令重排序。5.3 错误3未关闭线程池导致资源泄漏错误示例// 错误未关闭线程池核心线程长期存活导致资源泄漏 public static ThreadPoolExecutor getInstance() { if (instance null) { synchronized (SingletonThreadPool.class) { if (instance null) { instance new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(1000)); } } } return instance; }问题原因核心线程默认是“非守护线程”即使程序执行完成核心线程仍会存活导致JVM无法正常退出。解决方案添加JVM关闭钩子Shutdown Hook在JVM退出时关闭线程池。5.4 错误4线程池参数硬编码错误示例// 错误硬编码参数不便于维护和动态调整 private static final int CORE_POOL_SIZE 10; private static final int MAX_POOL_SIZE 20;问题原因不同环境dev/test/prod的服务器配置不同硬编码参数会导致资源利用率过低或过高。解决方案通过配置文件动态读取参数或基于CPU核心数动态计算。5.5 错误5未处理线程异常错误示例// 错误未设置未捕获异常处理器线程异常后静默终止 ThreadFactory threadFactory new ThreadFactory() { Override public Thread newThread(Runnable r) { return new Thread(r, pool-thread- threadNum.getAndIncrement()); } };问题原因线程执行任务时若抛出未捕获异常线程会直接终止且无法感知错误。解决方案通过thread.setUncaughtExceptionHandler设置异常处理器记录错误日志。六、总结单例线程池的设计核心单例线程池的设计核心是“唯一实例 合理配置 安全管控”唯一实例通过静态内部类、DCL或Spring Bean保证线程池全局唯一避免重复创建合理配置基于业务场景和服务器配置动态调整核心线程数、最大线程数、队列容量等参数遵循阿里巴巴开发手册安全管控处理线程异常、添加关闭钩子、避免反射破坏单例确保线程池的稳定运行和资源释放。通过本文的3种生产级实现方案和避坑指南你可以根据实际业务场景选择合适的单例线程池实现既夯实并发编程基础又能解决生产环境中的实际问题。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

连云港做网站多少钱中国保密在线网站培训系统

如何让搜索结果“会说话”?Elasticsearch 高亮实战全解析你有没有过这样的体验:在某个网站搜了一堆内容,点进结果列表后还得手动翻找关键词?明明系统说“找到了 23 条匹配记录”,可每条都长得差不多,根本看…

张小明 2025/12/26 3:07:32 网站建设

推广学校网站怎么做做网站有了空间在备案吗

GPT-SoVITS语音合成精度提升秘诀:数据预处理要点 在AI语音技术飞速发展的今天,我们早已不再满足于机械朗读式的“机器人音”。无论是虚拟主播、有声书生成,还是为视障人士提供无障碍阅读服务,用户都希望听到更自然、更具个性的声音…

张小明 2025/12/26 3:06:57 网站建设

响应式相册网站模板下载广州市天河区门户网站

如何快速掌握ArkLights:明日方舟玩家的终极完整指南 【免费下载链接】ArkLights 明日方舟速通 arknights 本仓库不再维护,请使用 https://github.com/AegirTech/ArkLights 项目地址: https://gitcode.com/gh_mirrors/ar/ArkLights ArkLights作为明…

张小明 2025/12/27 16:54:20 网站建设

成都旅行社网站建设投稿作文网站

5款VLC皮肤深度解析:从工具到艺术品的完美蜕变 【免费下载链接】VeLoCity-Skin-for-VLC Castom skin for VLC Player 项目地址: https://gitcode.com/gh_mirrors/ve/VeLoCity-Skin-for-VLC 每天面对VLC播放器单调的默认界面,是否让你感到审美疲劳…

张小明 2025/12/28 5:49:42 网站建设

wap网站定位大连网站建设意动科技

5个关键步骤彻底掌握付费墙绕过技术:Bypass Paywalls Clean实用指南 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 你是否曾经遇到过这样的情况:看到一篇很有…

张小明 2025/12/28 1:53:50 网站建设