Java性能优化设计模式篇

Java性能优化 · 设计模式篇

其实设计模式本身不直接提升性能,它是代码组织结构的最佳实践。当一种性能优化的实现途径恰好契合某种模式时,模式就成了这种优化的标准表达。

性能优化的目的是「让有限的资源(CPU/内存/线程/连接)服务更多业务请求」,模式只是把这种优化沉淀为可复用、可读的设计。

单例模式

单例模式解决的就是创建单一对象优化系统性能。一个类在系统中可能被多处频繁使用,如果每次都 new,会浪费资源;尤其在并发场景下,更需要保证「全局只有一份」。

单例模式的三要点:只能有一个实例;自行创建;自行向整个系统提供

现在的主要方式就两种:

  • 双重检测 + volatile
  • 静态内部类(推荐)

静态内部类骨架

1
2
3
4
5
6
7
8
9
public final class Singleton {
private Singleton() {}
private static class InnerSingleton {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return InnerSingleton.INSTANCE;
}
}

外部类加载时不会加载内部类,只有第一次调用 getInstance() 才会触发内部类加载与实例化,懒加载 + 线程安全 + 高性能全都要。


原型模式与享元模式

原型模式:加速对象创建,解决「创建过程太重」。

享元模式:减少对象数量,解决「对象总数太多」。

原型模式(Prototype)

核心问题:构造函数做了大量初始化(大数组、复杂计算),循环中反复 new 浪费 CPU。

关键代码骨架

1
2
3
4
5
6
7
8
9
10
11
class Prototype implements Cloneable {
public Prototype clone() {
Prototype prototype = null;
try {
prototype = (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}
  • Object.clone() 是 native 方法,直接操作内存二进制流,比 new 少了「调用构造函数」这一步。
  • 浅拷贝super.clone() 默认只复制基本类型与引用,引用类型成员仍指向同一对象。
  • 深拷贝:在 clone() 内对引用类型成员递归调用其 clone()

典型应用:Spring 中 @Scope("prototype") 的 bean,避免单例 + 全局变量被多次注入时被相互污染。

享元模式(Flyweight)

核心问题:大量对象其实共享同一份内部数据,反复创建浪费内存。

核心思想:把对象状态拆成内部状态(可共享、不随运行改变)外部状态(运行时不同值),内部状态相同的对象共用一份。

典型例子

  • String 常量池:String s1 = "hi"; String s2 = "hi"; s1 == s2true
  • 线程池:线程不是每次都重新创建,而是优先复用线程池中已经存在的线程。

对比与选型

维度 原型模式 享元模式
目的 加速单次对象创建过程 减少对象总数,共享内部状态
手段 clone() 替代 new 工厂 + 池化复用已有对象
适用场景 需要重复创建不同实例 可以共用同一内部数据的对象
内存占用 多个独立对象 单个共享对象 + 外部状态

选型决策:是否需要重复创建不同实例?是 → 原型。是否能共用同一内部数据?是 → 享元。

注意浅拷贝:引用类型成员只复制引用,修改克隆体对象会导致原对象也被修改!


观察者模式

在一些业务场景中,除关键流程外可能还有非关键流程。

一个常见的例子:用户注册账号后向其邮箱里发送一份欢迎邮件,但发送欢迎邮件并不是注册账号的核心流程。如果在注册账号的流程里完成发送邮件的操作,一方面功能没有那么单一了,另一方面会拖慢接口的响应时间。

一个简单的方案是:在注册完成后写消息到消息队列里,流量缓冲+业务解耦,这种方式偏向于“生产者消费者”模式。还有一种方式是在注册完成后发布事件,观察者观察到了这个事件,接着触发对应的处理,如 SpringBoot 里的 EventListener。

骨架代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// ========== 事件 ==========
public abstract class Event { }

public class UserRegisterEvent extends Event {
private final String username;
public UserRegisterEvent(String username) { this.username = username; }
public String getUsername() { return username; }
}

// ========== 观察者 ==========
public interface EventListener<E extends Event> {
void onEvent(E event);
}

public class EmailListener implements EventListener<UserRegisterEvent> {
@Override
public void onEvent(UserRegisterEvent event) {
// 发送欢迎邮件(非关键流程)
System.out.println("send welcome mail to " + event.getUsername());
}
}

// ========== 被观察者(事件总线) ==========
public class EventBus {
// 事件类型 → 该类型下注册的观察者列表
private final Map<Class<?>, List<EventListener>> listeners = new ConcurrentHashMap<>();

// 注册观察者:按事件类型归类
public <E extends Event> void register(Class<E> type, EventListener<E> listener) {
listeners.computeIfAbsent(type, k -> new CopyOnWriteArrayList<>()).add(listener);
}

// 发布事件:遍历该类型下的所有观察者,依次回调
// 实际项目中通常丢到线程池异步执行,避免拖慢主流程
public void publish(Event event) {
List<EventListener> list = listeners.get(event.getClass());
if (list == null) return;
for (EventListener listener : list) {
listener.onEvent(event);
}
}
}

// ========== 使用示例 ==========
EventBus bus = new EventBus();
bus.register(UserRegisterEvent.class, new EmailListener());

// 主流程:只发事件,不关心谁处理
bus.publish(new UserRegisterEvent("zhangsan"));

要点

  • 类型驱动Map<Class<?>, List<EventListener>> 按事件类型归类观察者,避免遍历所有监听器做 instanceof 判断。
  • 线程安全:用 ConcurrentHashMap + CopyOnWriteArrayList,注册/发布互不阻塞;CopyOnWriteArrayList 的写时复制适合「读多写少」的监听器列表。
  • 性能关键点publish() 里的 for 循环若同步执行会拖慢主流程,实际项目应丢到独立线程池异步执行(或像 Spring 的 @Async / @EventListener 配合 @EnableAsync);若观察者较多且允许乱序,可用 parallelStream() 并行触发。
  • vs 生产者消费者:观察者模式是「进程内同步/异步回调」,MQ 是「跨进程削峰」,前者更轻,后者更稳;能容忍丢失就先用观察者,要严格可靠才上 MQ。

面向对象设计模式里有几个不太常用,剩下的都有使用的场景,如装饰器模式实现功能增强;策略模式解决 if else 多判断;责任链模式实现流式处理,新增处理只需要新增节点等。


Java性能优化设计模式篇
https://zhuwenjie0716.github.io/2026/07/07/Java性能优化设计模式篇/
作者
Wenjie Zhu
发布于
2026年7月7日
许可协议