Java 并发最佳实践:构建高效的并发系统

张开发
2026/6/9 16:05:38 15 分钟阅读
Java 并发最佳实践:构建高效的并发系统
Java 并发最佳实践构建高效的并发系统别叫我大神叫我 Alex 就好。一、引言大家好我是 Alex。并发编程是 Java 开发中的重要组成部分它可以充分利用多核处理器的优势提高系统的性能和响应速度。然而并发编程也带来了许多挑战如线程安全、死锁、竞态条件等。今天我想和大家分享一下 Java 并发编程的最佳实践帮助大家构建高效、可靠的并发系统。二、Java 并发基础1. 线程基础线程创建使用Thread类或Runnable接口创建线程线程状态新建、就绪、运行、阻塞、死亡线程优先级设置线程优先级影响线程调度线程 daemon守护线程当所有非守护线程结束时自动结束2. 同步机制synchronized内置锁保证方法或代码块的原子性volatile保证变量的可见性和有序性Lock显式锁提供更灵活的锁定机制ReadWriteLock读写锁允许多个读操作并发执行3. 并发工具类CountDownLatch等待一组线程完成CyclicBarrier线程到达屏障时等待Semaphore控制并发访问的线程数Exchanger线程间交换数据Phaser可重用的同步屏障三、并发最佳实践1. 线程安全不可变对象使用不可变对象避免线程安全问题线程局部变量使用ThreadLocal存储线程局部变量原子类使用Atomic类进行原子操作线程安全集合使用ConcurrentHashMap、CopyOnWriteArrayList等线程安全集合示例// 使用不可变对象 public final class ImmutablePerson { private final String name; private final int age; public ImmutablePerson(String name, int age) { this.name name; this.age age; } public String getName() { return name; } public int getAge() { return age; } } // 使用 Atomic 类 private AtomicInteger count new AtomicInteger(0); public void increment() { count.incrementAndGet(); } // 使用线程安全集合 private ConcurrentHashMapString, String map new ConcurrentHashMap(); public void put(String key, String value) { map.put(key, value); }2. 线程池线程池类型FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor线程池参数核心线程数、最大线程数、keepAlive时间、工作队列、拒绝策略线程池监控监控线程池的状态和性能线程池调优根据任务类型和系统资源调整线程池参数示例// 创建线程池 ExecutorService executor Executors.newFixedThreadPool(10); // 提交任务 executor.submit(() - { // 执行任务 System.out.println(Task executed); }); // 关闭线程池 executor.shutdown(); try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); }3. 避免死锁锁顺序按照固定顺序获取锁锁超时使用tryLock()设置超时时间死锁检测使用工具检测死锁避免嵌套锁减少嵌套锁的使用示例// 按照固定顺序获取锁 public void transferMoney(Account from, Account to, double amount) { Account first from.getId() to.getId() ? from : to; Account second from.getId() to.getId() ? to : from; synchronized (first) { synchronized (second) { if (from.getBalance() amount) { from.withdraw(amount); to.deposit(amount); } } } } // 使用 tryLock() public boolean tryTransferMoney(Account from, Account to, double amount) { long timeout 1000; long start System.currentTimeMillis(); while (System.currentTimeMillis() - start timeout) { if (from.lock.tryLock()) { try { if (to.lock.tryLock()) { try { if (from.getBalance() amount) { from.withdraw(amount); to.deposit(amount); return true; } return false; } finally { to.lock.unlock(); } } } finally { from.lock.unlock(); } } try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } return false; }4. 并发性能优化减少锁竞争缩小锁范围使用细粒度锁使用无锁数据结构如ConcurrentHashMap、Atomic类使用并发工具如CompletableFuture、StreamAPI避免频繁上下文切换减少线程数量避免过度并发示例// 缩小锁范围 public void updateValue(String key, String value) { // 不需要同步的代码 synchronized (this) { // 需要同步的代码 map.put(key, value); } // 不需要同步的代码 } // 使用 CompletableFuture public CompletableFutureString fetchData(String url) { return CompletableFuture.supplyAsync(() - { // 异步获取数据 return Data from url; }); } // 使用 Stream API public void processData(ListString data) { data.parallelStream() .map(this::processItem) .forEach(System.out::println); }5. 异步编程CompletableFuture提供丰富的异步编程 APIReactor反应式编程库提供响应式流RxJava响应式编程库提供丰富的操作符Virtual Threads虚拟线程简化异步编程示例// 使用 CompletableFuture CompletableFutureString future1 CompletableFuture.supplyAsync(() - Hello); CompletableFutureString future2 CompletableFuture.supplyAsync(() - World); CompletableFutureString combined future1.thenCombine(future2, (s1, s2) - s1 s2); combined.thenAccept(System.out::println); // 使用虚拟线程 Runnable task () - { System.out.println(Running on virtual thread: Thread.currentThread()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Task completed); }; Thread.ofVirtual().start(task);四、并发常见问题及解决方案1. 竞态条件症状多线程同时访问和修改共享资源导致结果不一致解决方案使用同步机制synchronized、Lock使用原子类AtomicInteger、AtomicReference使用线程安全集合2. 死锁症状两个或多个线程互相等待对方释放锁导致所有线程阻塞解决方案按照固定顺序获取锁使用 tryLock() 设置超时时间减少嵌套锁的使用使用 Lock 而不是 synchronized3. 活锁症状线程不断尝试获取锁但总是失败导致线程忙等解决方案随机退避策略使用 exponential backoff避免无限重试4. 线程饥饿症状某些线程长时间无法获取资源导致任务无法执行解决方案使用公平锁合理设置线程优先级避免长任务占用锁5. 内存可见性症状一个线程修改了共享变量但另一个线程看不到修改后的值解决方案使用 volatile 关键字使用 synchronized 或 Lock使用 Atomic 类五、实战案例案例并发计数器需求实现一个高并发的计数器支持多线程同时递增实现public class ConcurrentCounter { private AtomicInteger count new AtomicInteger(0); public int increment() { return count.incrementAndGet(); } public int getCount() { return count.get(); } } // 测试 public class ConcurrentCounterTest { public static void main(String[] args) throws InterruptedException { ConcurrentCounter counter new ConcurrentCounter(); ExecutorService executor Executors.newFixedThreadPool(10); for (int i 0; i 1000; i) { executor.submit(() - { counter.increment(); }); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES); System.out.println(Final count: counter.getCount()); } }结果最终计数为 1000没有出现竞态条件性能良好能够处理高并发请求案例线程池优化需求优化线程池配置提高系统性能实现public class ThreadPoolOptimizer { private ExecutorService executor; public ThreadPoolOptimizer(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnable workQueue) { this.executor new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, new ThreadPoolExecutor.CallerRunsPolicy() ); } public void submitTask(Runnable task) { executor.submit(task); } public void shutdown() { executor.shutdown(); } public static void main(String[] args) { // 根据系统资源和任务类型配置线程池 int corePoolSize Runtime.getRuntime().availableProcessors(); int maxPoolSize corePoolSize * 2; long keepAliveTime 60L; TimeUnit unit TimeUnit.SECONDS; BlockingQueueRunnable workQueue new LinkedBlockingQueue(1000); ThreadPoolOptimizer optimizer new ThreadPoolOptimizer( corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue ); // 提交任务 for (int i 0; i 1000; i) { final int taskId i; optimizer.submitTask(() - { System.out.println(Task taskId executed by Thread.currentThread().getName()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }); } optimizer.shutdown(); } }结果线程池能够高效处理并发任务系统资源利用率得到提高任务执行时间减少六、总结Java 并发编程是构建高效系统的重要手段。通过合理地使用线程安全机制、线程池、并发工具类和异步编程我们可以构建出高性能、可靠的并发系统。同时我们也需要注意避免并发常见问题如竞态条件、死锁、活锁、线程饥饿和内存可见性问题。这其实可以更优雅一点。希望这篇文章能帮助大家更好地理解和实践 Java 并发编程的最佳实践。如果你有任何问题欢迎在评论区留言。关于作者我是 Alex一个在 CSDN 写 Java 架构思考的暖男。喜欢手冲咖啡养了一只叫Java的拉布拉多。如果我的文章对你有帮助欢迎关注我一起探讨 Java 技术的优雅之道。

更多文章