Java 并发程序性能优化:思路、方法与实践

一、前言

在高并发业务场景下(如电商秒杀、直播带货、金融交易),Java 并发程序的性能直接决定了系统的吞吐量、响应时间和稳定性。很多时候,简单的线程安全实现(如无脑加锁)虽然能保证数据一致性,但会带来严重的性能瓶颈 ------ 锁竞争导致线程阻塞、上下文切换开销飙升、CPU 利用率不足等问题。

本文将从性能优化的核心思路出发,拆解具体优化方法,并结合实战案例讲解如何落地这些优化手段,帮助大家构建 "高性能 + 线程安全" 的并发程序。

二、优化核心思路

优化的本质是在保证线程安全的前提下,最大化系统资源利用率,最小化不必要的性能开销,核心遵循三大思路:

1. 减少竞争:从根源降低锁冲突

并发程序的性能瓶颈大多来自锁竞争,线程因等待锁而阻塞,导致 CPU 资源无法充分利用。减少竞争的核心是" 隔离竞争资源,降低锁的竞争频率 ",具体表现为:

  • 缩小竞争范围:将全局锁改为局部锁,减少同一把锁的竞争线程数;
  • 减少竞争时间:缩短锁的持有时间,让锁尽快释放;
  • 消除竞争:用无锁方案替代有锁方案,从根源上避免锁竞争。

2. 提高并发:充分利用硬件资源

在多核 CPU 时代,优化的核心是最大化利用 CPU 核心资源,避免单线程瓶颈,让多线程并行执行有效任务,具体表现为:

  • 合理设置线程数:根据任务类型(CPU 密集 / IO 密集)配置最优线程数,避免线程过多导致上下文切换;
  • 任务拆分与并行:将大任务拆分为独立的小任务,通过线程池并行执行;
  • 提升资源利用率:减少线程阻塞(如 IO 阻塞、锁阻塞),让线程尽可能处于 RUNNABLE 状态。

3. 减少开销:消除不必要的性能损耗

并发程序中存在大量隐性性能开销(上下文切换、内存屏障、对象创建等),优化的核心是消除或减少这些无意义的开销,具体表现为:

  • 减少上下文切换:避免线程频繁阻塞 / 唤醒,使用无锁编程、合理设置线程数;
  • 减少内存开销:避免频繁创建临时对象(如线程局部变量复用、对象池),降低 GC 压力;
  • 优化 JVM 参数:通过 JVM 参数调整内存模型、锁机制,提升并发性能。

三、优化核心方法

1. 锁优化:减少锁竞争与开销

锁是并发程序的基础,也是性能瓶颈的重灾区,针对锁的优化是并发性能优化的核心,具体方法如下:

(1) 缩小锁粒度:从全局锁到局部锁

将对全局资源的锁竞争,转化为对局部资源的锁竞争,降低同一把锁的竞争概率。

典型案例: ConcurrentHashMap 的锁粒度演进

  • JDK7:采用分段锁( Segment ),将整个哈希表划分为 16 个分段,每个分段对应一把锁,线程仅竞争对应分段的锁,而非全局锁;

  • JDK8:进一步细化为节点锁,仅锁定哈希桶的头节点,而非整个分段,锁竞争范围更小。

**实战示例:**自定义分段锁优化全局锁竞争

java 复制代码
import java.util.concurrent.locks.ReentrantLock;
/**
 * 分段锁优化:将用户数据按用户ID哈希分段,减少锁竞争
 */
public class SegmentLockDemo {
    // 分段数:建议为2的幂次,与CPU核心数匹配
    private static final int SEGMENT_COUNT = 16;
    // 分段锁数组
    private final ReentrantLock[] segmentLocks;
    // 业务数据数组(按分段存储)
    private final Long[] userBalances;
    public SegmentLockDemo(int userCount) {
        this.segmentLocks = new ReentrantLock[SEGMENT_COUNT];
        this.userBalances = new Long[userCount];
        // 初始化分段锁与用户余额
        for (int i = 0; i < SEGMENT_COUNT; i++) {
            segmentLocks[i] = new ReentrantLock();
        }
        for (int i = 0; i < userCount; i++) {
            userBalances[i] = 0L;
        }
    }
    // 用户余额增加
    public void addBalance(int userId, long amount) {
        // 按userId计算分段索引,获取对应分段锁
        int segmentIndex = Math.abs(userId % SEGMENT_COUNT);
        ReentrantLock lock = segmentLocks[segmentIndex];
        // 加锁:仅竞争当前分段的锁
        lock.lock();
        try {
            userBalances[userId] += amount;
            System.out.println(Thread.currentThread().getName() + ":用户" + userId + "余额增加" + amount + ",当前余额:" + userBalances[userId]);
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        SegmentLockDemo demo = new SegmentLockDemo(1000);
        // 10个线程并发修改1000个用户余额,仅竞争分段锁,而非全局锁
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int userId = 0; userId < 1000; userId++) {
                    demo.addBalance(userId, 1);
                }
            }, "线程" + i).start();
        }
    }
}

(2) 缩短锁持有时间:仅在核心同步代码块加锁

锁的持有时间越长,竞争概率越高,性能开销越大。优化原则是" 能不加锁的代码不加锁,能放在锁外的代码放在锁外 "。

**反例(坏实践):**锁持有时间过长

java 复制代码
// 反例:整个方法加锁,包含非核心逻辑(日志打印、数据查询)
public synchronized void badAddBalance(int userId, long amount) {
    System.out.println(Thread.currentThread().getName() + ":开始修改用户" + userId + "余额");
    // 非核心逻辑:模拟数据查询(耗时操作)
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    // 核心同步逻辑:修改余额
    userBalances[userId] += amount;
    System.out.println(Thread.currentThread().getName() + ":用户" + userId + "余额修改完成");
}

**正例(好实践):**仅锁定核心同步代码块

java 复制代码
// 正例:仅锁定核心同步逻辑,非核心逻辑放在锁外
public void goodAddBalance(int userId, long amount) {
    System.out.println(Thread.currentThread().getName() + ":开始修改用户" + userId + "余额");
    // 非核心逻辑:模拟数据查询(耗时操作),放在锁外
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    // 仅锁定核心同步代码块,缩短锁持有时间
    synchronized (this) {
        userBalances[userId] += amount;
    }
    System.out.println(Thread.currentThread().getName() + ":用户" + userId + "余额修改完成");
}

(3) 锁替换:用更轻量的锁替代重量级锁

根据业务场景,选择性能更优的锁实现,核心替换方向:

  1. synchronized替代 ReentrantLock (低竞争场景):JDK1.8 后 synchronized 经过锁升级优化,低竞争场景下性能优于 ReentrantLock ,且自动释放锁,更安全;

  2. 读写锁( ReentrantReadWriteLock )替代独占锁:读多写少场景下,读写锁允许多个读线程同时访问,仅写线程互斥,大幅提升并发读性能;

  3. 无锁方案( volatile +CAS + 原子类)替代有锁方案:无锁编程避免线程阻塞,性能最优,适用于简单原子操作场景。

**实战示例:**ReentrantReadWriteLock 优化读多写少场景

java 复制代码
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * 读写锁优化:读多写少场景下,提升并发读性能
 */
public class ReadWriteLockDemo {
    // 读写锁
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    // 业务数据:用户余额
    private Long userBalance = 0L;
    // 读操作:获取用户余额(读多写少,使用读锁)
    public long getBalance() {
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + ":读取用户余额,当前余额:" + userBalance);
            // 模拟读操作耗时
            Thread.sleep(50);
            return userBalance;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return 0L;
        } finally {
            readLock.unlock();
        }
    }
    // 写操作:修改用户余额(写少,使用写锁)
    public void updateBalance(long amount) {
        writeLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + ":修改用户余额,增加" + amount);
            // 模拟写操作耗时
            Thread.sleep(100);
            userBalance += amount;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
        }
    }
    public static void main(String[] args) {
        ReadWriteLockDemo demo = new ReadWriteLockDemo();
        // 启动10个读线程(并发读,无阻塞)
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    demo.getBalance();
                }
            }, "读线程" + i).start();
        }
        // 启动2个写线程(互斥写,与读线程互斥)
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 2; j++) {
                    demo.updateBalance(100);
                }
            }, "写线程" + i).start();
        }
    }
}

(4) 避免锁嵌套:防止死锁与提升性能

锁嵌套会增加死锁风险,同时延长锁的持有时间(内层锁未释放时,外层锁也无法释放),应尽量避免。若必须使用嵌套锁,需严格统一锁的获取顺序。

2. 无锁编程:从根源消除锁竞争

无锁编程基于 volatile 和 CAS(Compare-And-Swap)实现,无需线程阻塞,性能远高于有锁方案,是高并发场景下的优选方案。

(1) 核心组件:JUC 原子类

JUC 提供了一系列原子类,封装了 CAS 操作,支持原子性操作,无需手动加锁:

  • 基本类型原子类: AtomicInteger 、 AtomicLong 、 AtomicBoolean ;
  • 引用类型原子类: AtomicReference 、 AtomicStampedReference (解决 ABA 问题);
  • 数组类型原子类: AtomicIntegerArray 、 AtomicLongArray ;
  • 累加器: LongAdder 、 DoubleAdder (高并发下性能优于 AtomicLong ,采用分段累加)。

(2) 实战示例 1: LongAdder 优化高并发计数

java 复制代码
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LongAdder;
/**
 * LongAdder vs AtomicLong:高并发计数性能优化
 * LongAdder采用分段累加,竞争时仅修改对应分段的计数器,性能更优
 */
public class LongAdderDemo {
    private static final int THREAD_COUNT = 20;
    private static final int TASK_COUNT = 100000;
    // 高并发计数优选LongAdder
    private static final LongAdder counter = new LongAdder();
    private static final CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
    public static void main(String[] args) throws InterruptedException {
        // 启动20个线程,每个线程计数10万次
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(() -> {
                for (int j = 0; j < TASK_COUNT; j++) {
                    counter.increment(); // 原子自增,无锁竞争
                }
                latch.countDown();
            }, "计数线程" + i).start();
        }
        // 等待所有线程执行完毕
        latch.await();
        System.out.println("最终计数结果:" + counter.sum()); // 预期:20*100000=2000000
    }
}

(3) 实战示例 2:CAS 实现无锁栈

java 复制代码
import java.util.concurrent.atomic.AtomicReference;
/**
 * CAS实现无锁栈:无需加锁,通过CAS保证入栈/出栈的原子性
 */
public class LockFreeStack<T> {
    // 原子引用存储栈顶节点
    private final AtomicReference<Node<T>> top = new AtomicReference<>();
    // 节点结构
    private static class Node<T> {
        private final T data;
        private Node<T> next;
        public Node(T data) {
            this.data = data;
        }
    }
    // 入栈操作:CAS更新栈顶
    public void push(T data) {
        Node<T> newNode = new Node<>(data);
        Node<T> oldTop;
        // CAS自旋:直到更新成功
        do {
            oldTop = top.get();
            newNode.next = oldTop;
            // CAS替换栈顶:若当前栈顶还是oldTop,则替换为newNode
        } while (!top.compareAndSet(oldTop, newNode));
        System.out.println(Thread.currentThread().getName() + ":入栈数据" + data);
    }
    // 出栈操作:CAS更新栈顶
    public T pop() {
        Node<T> oldTop;
        Node<T> newTop;
        // CAS自旋:直到更新成功
        do {
            oldTop = top.get();
            if (oldTop == null) {
                return null; // 栈为空
            }
            newTop = oldTop.next;
            // CAS替换栈顶:若当前栈顶还是oldTop,则替换为newTop
        } while (!top.compareAndSet(oldTop, newTop));
        System.out.println(Thread.currentThread().getName() + ":出栈数据" + oldTop.data);
        return oldTop.data;
    }
    public static void main(String[] args) {
        LockFreeStack<Integer> stack = new LockFreeStack<>();
        // 启动5个线程入栈
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> {
                stack.push(finalI);
            }, "入栈线程" + i).start();
        }
        // 启动5个线程出栈
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                stack.pop();
            }, "出栈线程" + i).start();
        }
    }
}

3. 线程池优化:最大化线程资源利用率

线程池是管理线程的核心工具,不合理的线程池配置会导致性能瓶颈(如线程过多、队列无界、拒绝策略不当),优化的核心是" 按需配置参数,监控并调优"。

(1) 核心参数优化:按任务类型精准配置

| 任务类型 | 核心线程数配置 | 最大线程数配置 | 任务队列选择 | 拒绝策略选择 |
| CPU 密集型(如数据计算) | CPU 核心数 + 1 | CPU 核心数 + 1 | 有界队列(容量适中,如 100) | AbortPolicy(快速失败) |
| IO 密集型(如网络请求、文件读写) | CPU 核心数 × 2 或 CPU 核心数 / (1 - 阻塞系数)(阻塞系数 0.8~0.9) | 核心线程数 × 2 | 有界队列(容量较大,如 1000) | CallerRunsPolicy(降级执行) |

混合型任务 拆分为 CPU 密集型 + IO 密集型,分别配置线程池 - 按子任务类型选择 按业务重要性选择

实战示例:按 IO 密集型任务配置最优线程池

java 复制代码
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * IO密集型任务线程池优化配置
 */
public class OptimalThreadPoolDemo {
    // 获取CPU核心数
    private static final int CPU_CORES = Runtime.getRuntime().availableProcessors();
    // 自定义线程工厂
    private static final ThreadFactory IO_THREAD_FACTORY = new ThreadFactory() {
        private final AtomicInteger count = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setName("io-thread-" + count.getAndIncrement());
            thread.setPriority(Thread.NORM_PRIORITY);
            return thread;
        }
    };
    // 拒绝策略:核心业务抛异常,非核心业务调用者执行
    private static final RejectedExecutionHandler IO_REJECT_HANDLER = new ThreadPoolExecutor.AbortPolicy();
    // IO密集型线程池:核心线程数=CPU_CORES*2,最大线程数=CPU_CORES*2,队列容量1000
    private static final ThreadPoolExecutor IO_THREAD_POOL = new ThreadPoolExecutor(
            CPU_CORES * 2,
            CPU_CORES * 2,
            60L,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000),
            IO_THREAD_FACTORY,
            IO_REJECT_HANDLER
    );
    // IO密集型任务:模拟网络请求
    static class IoTask implements Runnable {
        private final String taskId;
        public IoTask(String taskId) {
            this.taskId = taskId;
        }
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + ":执行IO任务" + taskId);
                // 模拟IO阻塞(如接口调用、数据库查询)
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    public static void main(String[] args) {
        // 提交1000个IO任务,测试线程池性能
        for (int i = 0; i < 1000; i++) {
            IO_THREAD_POOL.submit(new IoTask("TASK_" + i));
        }
        // 优雅关闭线程池
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            IO_THREAD_POOL.shutdown();
            try {
                if (!IO_THREAD_POOL.awaitTermination(10, TimeUnit.SECONDS)) {
                    IO_THREAD_POOL.shutdownNow();
                }
            } catch (InterruptedException e) {
                IO_THREAD_POOL.shutdownNow();
            }
        }));
    }
}

(2) 线程池监控:实时掌握运行状态

通过线程池提供的监控方法,实时监控线程池状态,及时发现性能瓶颈:

java 复制代码
// 线程池监控核心方法
public static void monitorThreadPool(ThreadPoolExecutor threadPool, String poolName) {
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    // 每5秒监控一次
    scheduler.scheduleAtFixedRate(() -> {
        System.out.println("===== " + poolName + " 线程池监控 =====");
        System.out.println("核心线程数:" + threadPool.getCorePoolSize());
        System.out.println("当前线程数:" + threadPool.getPoolSize());
        System.out.println("活跃线程数:" + threadPool.getActiveCount());
        System.out.println("最大线程数:" + threadPool.getMaximumPoolSize());
        System.out.println("任务队列长度:" + threadPool.getQueue().size());
        System.out.println("已执行任务总数:" + threadPool.getCompletedTaskCount());
        System.out.println("===========================\n");
    }, 0, 5, TimeUnit.SECONDS);
}

4. 其他优化手段:全方位提升并发性能

(1) 任务拆分与并行执行

将大任务拆分为独立的小任务,通过线程池并行执行,提升整体吞吐量。典型案例:Fork/Join 框架(适用于分治任务)。

java 复制代码
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
/**
 * Fork/Join框架:任务拆分与并行执行,优化大任务处理性能
 * 示例:计算1~1000000的累加和
 */
public class ForkJoinDemo extends RecursiveTask<Long> {
    // 任务拆分阈值:小于该值直接计算,大于该值拆分任务
    private static final long THRESHOLD = 10000;
    private final long start;
    private final long end;
    public ForkJoinDemo(long start, long end) {
        this.start = start;
        this.end = end;
    }
    // 任务执行逻辑
    @Override
    protected Long compute() {
        long sum = 0;
        // 判断是否需要拆分
        boolean canCompute = (end - start) <= THRESHOLD;
        if (canCompute) {
            // 直接计算
            for (long i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            // 拆分任务
            long middle = (start + end) / 2;
            ForkJoinDemo leftTask = new ForkJoinDemo(start, middle);
            ForkJoinDemo rightTask = new ForkJoinDemo(middle + 1, end);
            // 并行执行子任务
            leftTask.fork();
            rightTask.fork();
            // 获取子任务结果
            Long leftResult = leftTask.join();
            Long rightResult = rightTask.join();
            // 合并结果
            sum = leftResult + rightResult;
        }
        return sum;
    }
    public static void main(String[] args) {
        // Fork/Join线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        // 提交任务
        ForkJoinDemo task = new ForkJoinDemo(1, 1000000);
        Long result = forkJoinPool.invoke(task);
        System.out.println("1~1000000的累加和:" + result);
        // 关闭线程池
        forkJoinPool.shutdown();
    }
}

(2) 减少线程阻塞:使用异步编程

IO 阻塞(如数据库查询、网络请求)是导致线程闲置的主要原因,使用异步编程( CompletableFuture )让线程无需等待 IO 结果,可继续执行其他任务,提升线程利用率。

java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
 * CompletableFuture异步编程:减少IO阻塞,提升线程利用率
 */
public class CompletableFutureDemo {
    // 模拟IO任务:数据库查询
    public static String queryDb(String sql) {
        try {
            // 模拟IO阻塞
            Thread.sleep(1000);
            return "查询结果:" + sql;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return "查询失败";
        }
    }
    // 模拟IO任务:接口调用
    public static String callApi(String url) {
        try {
            // 模拟IO阻塞
            Thread.sleep(1500);
            return "接口响应:" + url;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return "接口调用失败";
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 异步执行数据库查询
        CompletableFuture<String> dbFuture = CompletableFuture.supplyAsync(() -> queryDb("SELECT * FROM user"));
        // 异步执行接口调用
        CompletableFuture<String> apiFuture = CompletableFuture.supplyAsync(() -> callApi("https://api.example.com/user"));
        // 主线程无需等待,可执行其他任务
        System.out.println("主线程执行其他业务逻辑...");
        // 获取异步任务结果(非阻塞,若未完成则等待)
        String dbResult = dbFuture.get();
        String apiResult = apiFuture.get();
        System.out.println(dbResult);
        System.out.println(apiResult);
    }
}

(3) 优化内存与 GC:减少性能抖动

并发程序中,频繁的 GC 会导致性能抖动,优化内存与 GC 的核心手段:

  • 减少临时对象创建:复用线程局部变量( ThreadLocal )、使用对象池(如 commons-pool );
  • 合理设置 JVM 内存参数: -Xms 、 -Xmx 设置为相同值,避免内存动态调整; -XX:NewRatio 调整新生代与老年代比例,减少 Full GC;
  • 使用 G1/ZGC 垃圾收集器:高并发场景下,G1/ZGC 的停顿时间更短,性能更稳定。

四、电商秒杀系统并发优化案例

1. 业务场景

电商秒杀系统的核心痛点:大量用户同时抢购有限商品,存在高并发读写、库存超卖、性能瓶颈等问题。

2. 优化前问题

  • 全局锁竞争:库存修改使用全局 synchronized 锁,并发性能极低;
  • 线程数不合理:手动创建线程,线程过多导致上下文切换频繁;
  • 同步 IO 阻塞:库存查询、订单创建为同步操作,线程利用率低;
  • 无缓存优化:每次查询库存都访问数据库,数据库压力过大。

3. 优化方案落地

  • 锁优化:使用 ReentrantLock (非公平锁)替代 synchronized ,并缩小锁粒度(按商品 ID 分段锁);
  • 线程池优化:配置 IO 密集型线程池,处理秒杀请求;
  • 无锁编程:使用 AtomicInteger 实现库存原子扣减,避免锁竞争;
  • 缓存优化:使用 Redis 缓存商品库存,减少数据库访问;
  • 异步编程:订单创建采用 CompletableFuture 异步执行,提升响应速度;
  • 流量控制:使用 Semaphore 限制并发请求数,防止系统过载。

4. 核心代码实现

java 复制代码
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 电商秒杀系统并发优化示例
 */
public class SeckillSystemOptimize {
    // 商品库存(原子类:无锁原子扣减)
    private static final AtomicInteger stock = new AtomicInteger(100);
    // 并发请求控制:限制100个并发请求
    private static final Semaphore semaphore = new Semaphore(100);
    // IO密集型线程池:处理秒杀请求
    private static final ThreadPoolExecutor SECKILL_THREAD_POOL = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() * 2,
            Runtime.getRuntime().availableProcessors() * 2,
            60L,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );
    // 秒杀核心方法
    public static void seckill(String userId, String goodsId) {
        try {
            // 1. 流量控制:获取许可,限制并发
            semaphore.acquire();
            // 2. 原子扣减库存:无锁竞争,性能最优
            int currentStock = stock.decrementAndGet();
            if (currentStock < 0) {
                System.out.println(userId + ":秒杀失败,商品已售罄");
                stock.incrementAndGet(); // 恢复库存
                return;
            }
            // 3. 异步创建订单:减少IO阻塞,提升响应速度
            CompletableFuture.runAsync(() -> {
                createOrder(userId, goodsId);
            }, SECKILL_THREAD_POOL);
            System.out.println(userId + ":秒杀成功,剩余库存:" + currentStock);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(userId + ":秒杀异常");
        } finally {
            // 释放许可
            semaphore.release();
        }
    }
    // 异步创建订单
    private static void createOrder(String userId, String goodsId) {
        try {
            // 模拟订单创建(数据库操作,IO阻塞)
            Thread.sleep(500);
            System.out.println("用户" + userId + ":订单创建成功,商品ID:" + goodsId);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("用户" + userId + ":订单创建失败");
        }
    }
    public static void main(String[] args) {
        // 模拟1000个用户秒杀
        for (int i = 0; i < 1000; i++) {
            String userId = "USER_" + i;
            String goodsId = "GOODS_001";
            SECKILL_THREAD_POOL.submit(() -> seckill(userId, goodsId));
        }
        // 优雅关闭线程池
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            SECKILL_THREAD_POOL.shutdown();
            try {
                if (!SECKILL_THREAD_POOL.awaitTermination(10, TimeUnit.SECONDS)) {
                    SECKILL_THREAD_POOL.shutdownNow();
                }
            } catch (InterruptedException e) {
                SECKILL_THREAD_POOL.shutdownNow();
            }
        }));
    }
}

五、性能优化评估与避坑指南

1. 性能评估指标

优化后需要通过量化指标验证效果,核心评估指标:

  • 吞吐量:单位时间内处理的请求数(越高越好);
  • 响应时间:平均 / 95%/99% 响应时间(越低越好);
  • CPU 利用率:多核 CPU 利用率应尽量均衡,避免单核瓶颈;
  • 锁竞争率:通过 JProfiler 等工具查看锁竞争次数(越低越好);
  • 上下文切换次数:通过 vmstat 命令查看( cs 列,越低越好)。

2. 避坑指南

  • 过度优化:优先保证业务正确性,再进行性能优化,避免为了优化而优化;
  • 忽略线程安全:无锁编程(如 CAS)需注意 ABA 问题,使用 AtomicStampedReference 解决;
  • 线程数越多越好:线程数超过最优值后,上下文切换开销会抵消并发收益;
  • 盲目使用无锁方案:复杂业务场景下,无锁编程的复杂度远高于有锁方案,可维护性差;
  • 忽略监控与压测:优化后必须通过高并发压测验证效果,同时上线后实时监控性能指标。

六、总结

Java 并发程序性能优化是一个系统性工程,核心围绕" 减少竞争、提高并发、减少开销 "三大思路展开。具体落地时,可从锁优化、无锁编程、线程池优化、任务拆分、异步编程等多个维度切入,根据业务场景选择合适的优化方法。

需要注意的是,性能优化没有银弹,不存在适用于所有场景的最优方案。在实际开发中,应遵循" 先定位瓶颈,再针对性优化,最后量化验证 "的流程:通过监控工具找到性能瓶颈(如锁竞争、线程阻塞、GC 频繁),然后选择对应的优化手段,最后通过压测验证优化效果,确保在保证线程安全的前提下,提升系统的并发性能和稳定性。

相关推荐
!停1 小时前
数据结构空间复杂度
java·c语言·算法
她说..1 小时前
验签实现方案整理(签名验证+防篡改+防重放)
java·经验分享·spring boot·java-ee·bladex
爱吃山竹的大肚肚2 小时前
异步导出方案
java·spring boot·后端·spring·中间件
没有bug.的程序员2 小时前
Spring Boot 与 Redis:缓存穿透/击穿/雪崩的终极攻防实战指南
java·spring boot·redis·缓存·缓存穿透·缓存击穿·缓存雪崩
草履虫建模2 小时前
Java 基础到进阶|专栏导航:路线图 + 目录(持续更新)
java·开发语言·spring boot·spring cloud·maven·基础·进阶
Zhu_S W2 小时前
Java多进程监控器技术实现详解
java·开发语言
Anastasiozzzz2 小时前
LeetCodeHot100 347. 前 K 个高频元素
java·算法·面试·职场和发展
青芒.2 小时前
macOS Java 多版本环境配置完全指南
java·开发语言·macos
Hx_Ma162 小时前
SpringMVC框架(上)
java·后端