性能优化:让系统跑得更快
性能优化是技术含量最高的工作之一。
很多人优化的第一反应是"加缓存"、"换数据库"、"上分布式"——但如果没有数据支撑,优化就是盲目的。
优化的正确姿势
先测量,再优化。没有数据的优化是耍流氓。
优化前先问:
- 慢在哪里?(定位瓶颈)
- 有多慢?(量化指标)
- 为什么慢?(分析原因)
优化后再问: 4. 优化后快了多少?(验证效果)
常见优化方向
| 方向 | 常见问题 | 优化手段 |
|---|---|---|
| 内存 | 对象创建过多 | 对象复用、减少 GC |
| 计算 | 算法复杂度高 | 换算法 |
| IO | 同步阻塞 | 异步、批量 |
| 数据库 | SQL 慢 | 加索引、改写 SQL |
字符串优化
字符串拼接是性能问题的高发区:
java
// ❌ 循环内拼接,O(n²)
String result = "";
for (int i = 0; i < 1000; i++) {
result += "item" + i;
}
// ✅ StringBuilder,O(n)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("item").append(i);
}
// ✅ JDK 8+ 用 StringJoiner
String result = IntStream.range(0, 1000)
.mapToObj(i -> "item" + i)
.collect(Collectors.joining(","));集合优化
java
// ✅ 预估容量,减少扩容
List<String> list = new ArrayList<>(10000);
// ✅ 循环中删除用 removeIf
list.removeIf(item -> item.length() > 10);
// ✅ 用迭代器而不是 for-each 当要边遍历边删除
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().length() > 10) {
it.remove();
}
}缓存优化
重复计算的结果缓存起来:
java
// ❌ 每次都重新计算
public String getFullName(Long userId) {
User user = userRepository.findById(userId);
return user.getFirstName() + user.getLastName();
}
// ✅ 用 Map 缓存
private final Map<Long, String> fullNameCache = new ConcurrentHashMap<>();
public String getFullName(Long userId) {
return fullNameCache.computeIfAbsent(userId, id -> {
User user = userRepository.findById(id);
return user.getFirstName() + user.getLastName();
});
}批量操作
减少数据库/网络调用次数:
java
// ❌ 循环中逐条插入
for (OrderItem item : items) {
orderItemRepository.save(item);
}
// ✅ 批量插入
orderItemRepository.saveAll(items);
// ❌ 循环中逐条查询
for (Long userId : userIds) {
User user = userRepository.findById(userId); // N 次数据库查询
}
// ✅ 批量查询
Map<Long, User> userMap = userRepository.findAllById(userIds).stream()
.collect(Collectors.toMap(User::getId, u -> u));总结
- 先测量:用 Arthas / Profiler 找到真正的瓶颈
- 避免过早优化:先保证代码可读,性能问题出现再优化
- 选择合适的数据结构:数据结构选对了,性能自然好
- 批量操作:减少 IO 次数是优化的捷径
优化的本质是减少浪费:减少不必要的计算、不必要的 IO、不必要的内存分配。
