Java并发编程最佳实践之构建高并发、可伸缩的应用实例

 更新时间:2026年04月19日 09:36:03   作者:程序员鸭梨  
Java并发编程是Java语言中最为复杂且核心的高级特性之一,其本质在于如何在多线程环境下高效、安全、可预测地协调多个执行单元对共享资源的访问与协作,这篇文章主要介绍了Java并发编程最佳实践之构建高并发、可伸缩的应用实例,需要的朋友可以参考下

一、引言

在现代应用开发中,并发编程已经成为一个不可或缺的技能。随着多核处理器的普及,充分利用系统资源、提高应用性能成为了开发者的重要目标。Java 作为企业级应用的主流语言,提供了丰富的并发编程工具和 API。今天,我想和大家分享一下 Java 并发编程的最佳实践,帮助大家构建高并发、可伸缩的应用。

二、并发编程基础

1. 线程安全

  • 原子性:操作要么全部执行,要么全部不执行
  • 可见性:一个线程对共享变量的修改,其他线程能够立即看到
  • 有序性:程序执行的顺序按照代码的先后顺序执行

2. 并发工具类

基本工具

  • synchronized:同步关键字
  • volatile:保证可见性
  • final:不可变对象

并发集合

  • ConcurrentHashMap:线程安全的哈希表
  • CopyOnWriteArrayList:写时复制的数组
  • BlockingQueue:阻塞队列

线程池

  • Executors:线程池工厂
  • ThreadPoolExecutor:线程池实现

三、最佳实践

1. 线程池使用

合理配置线程池

// 好的做法
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,          // 核心线程数
    maximumPoolSize,       // 最大线程数
    keepAliveTime,         // 线程存活时间
    TimeUnit.SECONDS,      // 时间单位
    new LinkedBlockingQueue<>(queueCapacity), // 任务队列
    new ThreadFactoryBuilder().setNameFormat("worker-%d").build(), // 线程工厂
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

// 不好的做法
ExecutorService executor = Executors.newFixedThreadPool(10); // 可能导致 OOM

线程池监控

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(100);
    executor.setThreadNamePrefix("task-");
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    executor.initialize();
    return executor;
}

2. 锁的使用

选择合适的锁

  • synchronized:适合简单场景
  • ReentrantLock:适合复杂场景,支持公平锁和非公平锁
  • ReadWriteLock:适合读多写少的场景
  • StampedLock:JDK 8+ 提供,性能更好

锁优化

  • 减少锁的范围:只锁定必要的代码块
  • 使用无锁数据结构:如 Atomic 类
  • 避免死锁:合理安排锁的获取顺序

示例

// 好的做法
public class Counter {
    private final AtomicInteger count = new AtomicInteger(0);
    public void increment() {
        count.incrementAndGet();
    }
    public int getCount() {
        return count.get();
    }
}
// 不好的做法
public class Counter {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public synchronized int getCount() {
        return count;
    }
}

3. 并发集合使用

选择合适的集合

场景推荐集合
高并发读写ConcurrentHashMap
读多写少CopyOnWriteArrayList
生产者-消费者BlockingQueue
线程安全队列ConcurrentLinkedQueue

示例

// 高并发读写
private final Map<String, User> userMap = new ConcurrentHashMap<>();
// 读多写少
private final List<User> userList = new CopyOnWriteArrayList<>();
// 生产者-消费者
private final BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<>();

4. 线程安全的单例模式

枚举单例

// 最佳实践
public enum Singleton {
    INSTANCE;
    private final UserService userService;
    Singleton() {
        userService = new UserService();
    }
    public UserService getUserService() {
        return userService;
    }
}
// 使用
UserService userService = Singleton.INSTANCE.getUserService();

双重检查锁

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

5. 原子操作

Atomic 类

  • AtomicInteger:原子整数
  • AtomicLong:原子长整型
  • AtomicReference:原子引用
  • AtomicStampedReference:带版本号的原子引用

示例

// 原子更新
AtomicInteger counter = new AtomicInteger(0);
// 递增
int value = counter.incrementAndGet();
// 比较并交换
boolean updated = counter.compareAndSet(expectedValue, newValue);

6. 并发工具

CountDownLatch

// 等待多个线程完成
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    executor.submit(() -> {
        try {
            // 执行任务
        } finally {
            latch.countDown();
        }
    });
}
// 等待所有任务完成
latch.await();

CyclicBarrier

// 等待多个线程到达屏障
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("所有线程已到达屏障");
});
for (int i = 0; i < 3; i++) {
    executor.submit(() -> {
        try {
            // 执行任务
            barrier.await();
            // 继续执行
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}

Semaphore

// 控制并发访问数
Semaphore semaphore = new Semaphore(5);
for (int i = 0; i < 10; i++) {
    executor.submit(() -> {
        try {
            semaphore.acquire();
            try {
                // 执行任务
            } finally {
                semaphore.release();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

CompletableFuture

// 异步执行
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务
    return "Result 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务
    return "Result 2";
});
// 组合结果
CompletableFuture<String> combined = future1.thenCombine(future2, (result1, result2) -> {
    return result1 + ", " + result2;
});
// 获取结果
String result = combined.join();

四、并发编程的挑战

1. 死锁

避免死锁

  • 按固定顺序获取锁
  • 使用超时机制
  • 使用 Lock 接口的 tryLock() 方法

示例

// 好的做法:按固定顺序获取锁
public void transferMoney(Account from, Account to, int amount) {
    int fromHash = System.identityHashCode(from);
    int toHash = System.identityHashCode(to);
    if (fromHash < toHash) {
        synchronized (from) {
            synchronized (to) {
                from.debit(amount);
                to.credit(amount);
            }
        }
    } else if (fromHash > toHash) {
        synchronized (to) {
            synchronized (from) {
                from.debit(amount);
                to.credit(amount);
            }
        }
    } else {
        // 使用额外的锁
        synchronized (lock) {
            synchronized (from) {
                synchronized (to) {
                    from.debit(amount);
                    to.credit(amount);
                }
            }
        }
    }
}

2. 活锁

避免活锁

  • 引入随机延迟
  • 使用优先级机制
  • 避免无限重试

3. 饥饿

避免饥饿

  • 使用公平锁
  • 合理设置线程优先级
  • 避免长时间持有锁

五、实战案例

案例:电商系统库存管理

需求

  • 高并发下的库存管理
  • 避免超卖
  • 保证数据一致性

实现

public class InventoryService {
    private final ConcurrentHashMap<String, AtomicInteger> inventory = new ConcurrentHashMap<>();
    public boolean decreaseStock(String productId, int quantity) {
        AtomicInteger stock = inventory.computeIfAbsent(productId, k -> new AtomicInteger(0));
        while (true) {
            int currentStock = stock.get();
            if (currentStock < quantity) {
                return false; // 库存不足
            }
            if (stock.compareAndSet(currentStock, currentStock - quantity)) {
                return true; // 成功减少库存
            }
            // 竞争失败,重试
        }
    }
    public int getStock(String productId) {
        AtomicInteger stock = inventory.get(productId);
        return stock != null ? stock.get() : 0;
    }
    public void increaseStock(String productId, int quantity) {
        AtomicInteger stock = inventory.computeIfAbsent(productId, k -> new AtomicInteger(0));
        stock.addAndGet(quantity);
    }
}

六、总结

Java 并发编程是一个复杂但强大的工具,通过合理使用并发工具和最佳实践,我们可以构建高并发、可伸缩的应用。在实践中,我们需要根据具体场景选择合适的并发策略,避免常见的并发问题,确保应用的正确性和性能。

这其实可以更优雅一点。

到此这篇关于Java并发编程最佳实践之构建高并发、可伸缩的应用实例的文章就介绍到这了,更多相关Java构建高并发、可伸缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot如何通过接口实现动态二维码的定时刷新

    springboot如何通过接口实现动态二维码的定时刷新

    这篇文章主要为大家详细介绍了springboot如何通过接口实现动态二维码的定时刷新功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-05-05
  • 解决idea中servlet报红问题

    解决idea中servlet报红问题

    这篇文章主要介绍了解决idea中servlet报红问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • Springboot服务引用Nacos中新增的配置文件失败问题及解决

    Springboot服务引用Nacos中新增的配置文件失败问题及解决

    这篇文章主要介绍了Springboot服务引用Nacos中新增的配置文件失败问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • java读取txt文件内容简单举例

    java读取txt文件内容简单举例

    这篇文章主要给大家介绍了关于java读取txt文件内容简单举例的相关资料,通常我们可以直接通过文件流来读取txt文件的内容,文中给出了详细的代码示例,需要的朋友可以参考下
    2023-07-07
  • Java实现字符串反转

    Java实现字符串反转

    这篇文章介绍了Java实现字符串反转的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Java之String字符串在JVM中的存储及其内存地址的问题

    Java之String字符串在JVM中的存储及其内存地址的问题

    这篇文章主要介绍了Java之String字符串在JVM中的存储及其内存地址的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Java 内存安全问题的注意事项

    Java 内存安全问题的注意事项

    内存安全问题是每个程序员开发时都需要面对的问题,本文介绍了JVM管理内存的原理以及内存安全问题需要注意的地方,有此需求的朋友可以参考下本文
    2021-06-06
  • Java设计模式--适配器模式详解

    Java设计模式--适配器模式详解

    这篇文章主要介绍了java设计模式之适配器模式Adapter的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 详解SpringBoot依赖注入和使用配置文件

    详解SpringBoot依赖注入和使用配置文件

    这篇文章主要介绍了SpringBoot依赖注入和使用配置文件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • Spring中@Controller与@RestController核心解析实战指南

    Spring中@Controller与@RestController核心解析实战指南

    本文系统解析了Spring MVC中@Controller、@RestController和@RequestMapping的核心功能与最佳实践,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-11-11

最新评论