在现代软件开发中,仅仅实现功能正确性已远远不够。随着用户规模增长、业务复杂度上升以及网络攻击手段的日益精进,性能与安全成为了衡量软件质量的核心维度。性能调优能保证系统在高并发下依然响应迅速、资源利用率合理;安全调优则能抵御恶意攻击,保护数据资产与用户隐私。
本文将从进阶视角出发,系统性地阐述性能调优与安全调优的关键技术点,结合大量代码示例与底层原理分析,帮助开发者构建高可靠、高可用的企业级应用。
第一部分:性能调优
性能优化并非盲目地“加速”,而是基于度量、定位瓶颈、有针对性改进的闭环过程。常见的性能目标包括:低延迟(Latency)、高吞吐量(Throughput)、合理的资源消耗(CPU/内存/磁盘/网络)。
1. 算法与数据结构优化
选择正确的算法和数据结构是性能优化的第一道防线。一个 O(n²) 的算法在数据量增长时会导致性能雪崩。
1.1 时间复杂度与空间复杂度权衡
示例:查找重复元素
// 糟糕的做法:双重循环 O(n²)
public List<Integer> findDuplicatesBad(int[] nums) {
List<Integer> duplicates = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] == nums[j] && !duplicates.contains(nums[i])) {
duplicates.add(nums[i]);
}
}
}
return duplicates;
}
// 优化的做法:使用 HashSet O(n)
public List<Integer> findDuplicatesGood(int[] nums) {
Set<Integer> seen = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int num : nums) {
if (!seen.add(num)) { // add 返回 false 说明已存在
duplicates.add(num);
}
}
return new ArrayList<>(duplicates);
}
1.2 选择正确的集合实现
HashMap vs TreeMap:HashMap 平均 O(1) 插入/查找,但无序;TreeMap O(log n) 且有序。除非需要排序或范围查询,否则优先使用 HashMap。
ArrayList vs LinkedList:随机访问频繁用 ArrayList(O(1))(nbcrjg.com),频繁在中间插入/删除用 LinkedList(但实际中 ArrayList 配合 System.arraycopy 在多数场景下仍比 LinkedList 快,因为内存连续且 CPU 缓存友好)。
LinkedHashMap:可用于实现简单的 LRU 缓存。
// 使用 LinkedHashMap 实现 LRU 缓存 (容量为 3)
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int maxSize;
public LRUCache(int maxSize) {
super(16, 0.75f, true); // accessOrder=true
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize;
}
}
2. 多线程与并发优化
2.1 线程池的正确使用
避免直接 new Thread(),使用线程池管理生命周期,减少线程创建销毁的开销。
线程池参数详解:
corePoolSize:核心线程数,即使空闲也不会销毁(除非设置 allowCoreThreadTimeOut)
maximumPoolSize:最大线程数,当队列满时才会增加线程至该值
workQueue:任务队列,可选择 ArrayBlockingQueue(有界)、LinkedBlockingQueue(默认无界)、SynchronousQueue(直接移交)
RejectedExecutionHandler:拒绝策略(Abort、CallerRuns、Discard、DiscardOldest)
// 不推荐:允许队列无限增长,可能导致 OOM
ExecutorService badPool = Executors.newFixedThreadPool(10); // 使用无界队列
// 推荐:自定义有界队列与合理拒绝策略
ExecutorService goodPool = new ThreadPoolExecutor(
5, // corePoolSize
20, // maximumPoolSize
60L, TimeUnit.SECONDS, // 空闲线程存活时间
new ArrayBlockingQueue<>(100), // 有界队列
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时,让提交任务的线程执行
);
2.2 锁优化
细粒度锁 vs 粗粒度锁
// 粗粒度锁:整个方法加锁,并发性能差
public synchronized void updateAccount1(long accountId, double amount) {
Account acc = accounts.get(accountId);
acc.setBalance(acc.getBalance() + amount);
}
// 细粒度锁:只锁定需要修改的数据片段
private final ConcurrentHashMap<Long, Account> accounts = new ConcurrentHashMap<>();
public void updateAccount2(long accountId, double amount) {
// ConcurrentHashMap 内部分段锁,读无锁,写仅锁定对应段
accounts.compute(accountId, (id, acc) -> {
acc.setBalance(acc.getBalance() + amount);
return acc;
});
}
使用 StampedLock 实现乐观读
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead(); // 乐观读,不阻塞写
double currentX = x, currentY = y;
if (!sl.validate(stamp)) { // 如果有写操作介入,则升级为悲观读
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
2.3 无锁编程与原子类
使用 AtomicInteger、LongAdder、ConcurrentLinkedQueue 等避免锁竞争。
// 高并发计数场景
// 错误:使用 synchronized 或 volatile 无法保证原子性
private volatile int count = 0;
synchronized void increment() { count++; } // 锁导致性能下降
// 较好:AtomicInteger,基于 CAS
private AtomicInteger atomicCount = new AtomicInteger(0);
void incrementAtomic() {
atomicCount.incrementAndGet(); // 无锁,自旋
}
// 最佳:LongAdder,分段累加,适合写多读少
private LongAdder adder = new LongAdder();
void incrementAdder() {
adder.increment();
}
long getTotal() { return adder.sum(); }
2.4 异步与 CompletableFuture
将耗时 I/O 或计算异步化,避免阻塞主线程。
// 同步阻塞方式
public String fetchUserDataSync() {
String user = userService.getUser(); // 耗时 100ms
String order = orderService.getOrder(); // 耗时 200ms
return user + order; // 总耗时 300ms
}
// 异步并行方式
public CompletableFuture<String> fetchUserDataAsync() {
CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> userService.getUser());
CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> orderService.getOrder());
return userFuture.thenCombine(orderFuture, (u, o) -> u + o); // 总耗时约 200ms (Max)
}