Java性能瓶颈案例

wen java案例 1

本文目录导读:

Java性能瓶颈案例

  1. 案例1:字符串拼接导致的性能问题
  2. 案例2:数据库连接未关闭
  3. 案例3:集合使用不当
  4. 案例4:同步过度
  5. 案例5:大对象导致GC问题
  6. 案例6:Web应用性能问题
  7. 性能调优工具使用建议

我来分享几个真实的Java性能瓶颈案例,涵盖常见的性能问题及其解决方案。

案例1:字符串拼接导致的性能问题

问题场景

// 错误示范:循环中大量字符串拼接
public String processData(List<User> users) {
    String result = "";
    for (User user : users) {
        result += "Name: " + user.getName() + ", ";
        result += "Age: " + user.getAge() + "; ";
    }
    return result;
}

性能分析

  • 每次操作都会创建新的String对象
  • 循环100万次会产生100万个临时对象
  • CPU和内存开销巨大

解决方案

// 正确方式:使用StringBuilder
public String processData(List<User> users) {
    StringBuilder sb = new StringBuilder(users.size() * 20);
    for (User user : users) {
        sb.append("Name: ").append(user.getName()).append(", ");
        sb.append("Age: ").append(user.getAge()).append("; ");
    }
    return sb.toString();
}
// 高并发场景:ThreadLocal复用StringBuilder
public class ThreadLocalStringBuilder {
    private static final ThreadLocal<StringBuilder> TL = 
        ThreadLocal.withInitial(() -> new StringBuilder(1024));
    public static String buildString(List<User> users) {
        StringBuilder sb = TL.get();
        sb.setLength(0); // 清空
        // ... 拼接逻辑
        return sb.toString();
    }
}

案例2:数据库连接未关闭

问题场景

// 错误示范:连接泄漏
public List<Order> getOrders() {
    Connection conn = null;
    try {
        conn = DriverManager.getConnection(url, user, password);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM orders");
        // 处理结果集...
        return processOrders(rs);
    } catch (SQLException e) {
        log.error("DB error", e);
        return Collections.emptyList();
    }
    // 没有finally块,连接永不关闭
}

解决方案

// 正确方式:try-with-resources
public List<Order> getOrders() {
    String sql = "SELECT * FROM orders WHERE status = ?";
    try (Connection conn = dataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, "ACTIVE");
        try (ResultSet rs = ps.executeQuery()) {
            List<Order> orders = new ArrayList<>();
            while (rs.next()) {
                orders.add(Order.fromResultSet(rs));
            }
            return orders;
        }
    } catch (SQLException e) {
        log.error("DB error", e);
        return Collections.emptyList();
    }
}

案例3:集合使用不当

问题场景

// 错误示范:频繁扩容+错误的数据结构
public void processItems() {
    // ArrayList初始容量太小,频繁扩容
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 1000000; i++) {
        list.add(i);
    }
    // 频繁查找使用List,时间复杂度O(n)
    boolean exists = list.contains(999999);
    // 遍历删除使用ArrayList
    for (Integer num : list) {
        if (num % 2 == 0) {
            list.remove(num); // ConcurrentModificationException
        }
    }
}

解决方案

// 正确方式:合理选择数据结构
public void processItems() {
    // 预估容量,避免扩容
    List<Integer> list = new ArrayList<>(1000000);
    for (int i = 0; i < 1000000; i++) {
        list.add(i);
    }
    // 频繁查找使用HashSet,时间复杂度O(1)
    Set<Integer> set = new HashSet<>(list);
    boolean exists = set.contains(999999);
    // 遍历删除使用迭代器或removeIf
    list.removeIf(num -> num % 2 == 0);
    // 或者使用效率更高的方式
    List<Integer> filtered = list.stream()
        .filter(num -> num % 2 != 0)
        .collect(Collectors.toList());
}

案例4:同步过度

问题场景

// 错误示范:过度使用同步
public class Counter {
    private int count = 0;
    // 每个线程独立不需要同步
    public synchronized void increment() {
        count++;
    }
    // 读操作也不需要同步(如果允许短暂不一致)
    public synchronized int getCount() {
        return count;
    }
    // 整个方法同步,包含耗时的IO操作
    public synchronized void processWithIO() {
        doSomeIOOperation(); // 耗时操作
        count++;
        sendNotification();  // 外部API调用
    }
}

解决方案

// 正确方式:减少锁的粒度
public class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    // 使用原子操作
    public void increment() {
        count.incrementAndGet();
    }
    public int getCount() {
        return count.get();
    }
    private final Object lock = new Object();
    // 只对需要保护的代码块加锁
    public void processWithIO() {
        doSomeIOOperation(); // 不需要加锁
        synchronized(lock) {
            // 只保护关键操作
            int current = count.get();
            count.set(current + 1);
        }
        // 异步发送通知
        CompletableFuture.runAsync(this::sendNotification);
    }
}

案例5:大对象导致GC问题

问题场景

// 错误示范:频繁创建大数组
public class DataProcessor {
    public void processBatch() {
        for (int i = 0; i < 1000; i++) {
            // 每次循环创建大数组,导致频繁GC
            byte[] data = new byte[10 * 1024 * 1024];
            // 处理数据...
        }
    }
}

解决方案

// 正确方式:复用缓冲区和池化技术
public class DataProcessor {
    private static final int BUFFER_SIZE = 10 * 1024 * 1024;
    private final byte[] fixedBuffer = new byte[BUFFER_SIZE];
    // 对象池
    private static final ThreadLocal<byte[]> bufferPool = 
        ThreadLocal.withInitial(() -> new byte[BUFFER_SIZE]);
    public void processBatch() {
        for (int i = 0; i < 1000; i++) {
            byte[] data = bufferPool.get();
            // 注意:每次使用前需清空
            Arrays.fill(data, (byte) 0);
            // 处理数据...
        }
    }
}

案例6:Web应用性能问题

问题场景

// 错误示范:Response非常慢
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    // 1. 同步阻塞调用
    // 2. 每次都查数据库
    // 3. 返回大结果集
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.getAllUsersWithDetails();
    }
    // 大量重复查询
    @GetMapping("/user/{id}/details")
    public UserDetailView getUserDetail(@PathVariable String id) {
        return userService.getUserDetailById(id); // 每次都访问DB
    }
}

解决方案

@RestController
public class UserController {
    @Autowired
    private CacheManager cacheManager;
    @Autowired
    private UserService userService;
    // 1. 分页查询
    // 2. 使用缓存
    // 3. 异步处理
    @GetMapping("/users")
    public Page<UserSummary> getUsers(@RequestParam(defaultValue = "1") int page,
                                      @RequestParam(defaultValue = "20") int size) {
        String cacheKey = String.format("users:%d:%d", page, size);
        Page<UserSummary> cached = cacheManager.get(cacheKey, Page.class);
        if (cached != null) {
            return cached;
        }
        Page<UserSummary> result = userService.getPage(page, size);
        cacheManager.put(cacheKey, result, Duration.ofMinutes(10));
        return result;
    }
    // 缓存热点数据
    @Cacheable(value = "userDetail", key = "#id")
    @GetMapping("/user/{id}/details")
    public CompletableFuture<UserDetailView> getUserDetail(@PathVariable String id) {
        return CompletableFuture.supplyAsync(() -> userService.getUserDetailById(id));
    }
}

性能调优工具使用建议

CPU分析

# 使用jstack查看线程状态
jstack -l <pid> > thread_dump.txt
# 使用VisualVM/JMC进行CPU分析
# 使用async-profiler
./profiler.sh -c cpu -d 30 -o html <pid>

内存分析

# 堆转储
jmap -dump:format=b,file=heap.hprof <pid>
# 使用MAT/Eclipse MAT分析内存泄漏
# 查看GC日志
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log

JVM参数调优示例

java -Xms4g -Xmx4g \
     -XX:NewRatio=2 \
     -XX:SurvivorRatio=8 \
     -XX:MaxTenuringThreshold=15 \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=100 \
     -XX:+DisableExplicitGC \
     -XX:+HeapDumpOnOutOfMemoryError \
     -XX:HeapDumpPath=/path/to/dump \
     -Dspring.profiles.active=prod \
     -jar application.jar

这些案例展示了Java性能问题的多样性和复杂性,关键在于:

  • 合理使用数据结构
  • 注意资源管理
  • 减少锁竞争
  • 合理使用缓存
  • 定期进行性能分析和调优

抱歉,评论功能暂时关闭!