java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java构建高并发、可伸缩

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

作者:程序员鸭梨

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

一、引言

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

二、并发编程基础

1. 线程安全

2. 并发工具类

基本工具

并发集合

线程池

三、最佳实践

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. 锁的使用

选择合适的锁

锁优化

示例

// 好的做法
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 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. 死锁

避免死锁

示例

// 好的做法:按固定顺序获取锁
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构建高并发、可伸缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文