在JVM应用开发中,保证对象唯一性是很多业务场景的基础需求,比如用户会话对象、全局配置管理器、数据库连接池等,都需要避免重复创建实例导致资源浪费或者数据不一致。常见的实现思路有单例模式、工厂模式结合会话管理两种主流方案,下面分别介绍其实现方式和适用场景。

单例模式实现对象唯一性
单例模式是最直接的保证JVM内对象唯一性的方式,其核心思路是私有化构造方法,通过静态方法提供全局唯一的实例。常见的实现方式有饿汉式、懒汉式、双重检查锁等。
双重检查锁单例实现
双重检查锁单例既保证了线程安全,又避免了每次获取实例都加锁的性能损耗,是实际开发中使用较多的单例实现方式。
public class SessionManager {
// 使用volatile保证多线程下的可见性和禁止指令重排
private static volatile SessionManager instance;
// 私有化构造方法,防止外部直接new实例
private SessionManager() {}
// 全局获取实例的静态方法
public static SessionManager getInstance() {
if (instance == null) {
synchronized (SessionManager.class) {
if (instance == null) {
instance = new SessionManager();
}
}
}
return instance;
}
// 会话管理相关业务方法
public void addSession(String sessionId, Object sessionData) {
// 会话存储逻辑
}
}
单例模式的优点是实现简单,调用方便,但缺点是扩展性较差,如果后续需要支持多个不同配置的会话管理器实例,单例模式就无法满足需求。
工厂模式结合会话管理实现对象唯一性
工厂模式通过统一的工厂类控制对象的创建过程,结合会话管理机制,可以在JVM内为不同的会话标识维护唯一的对象实例,比单例模式更灵活。
实现思路
核心逻辑是工厂类内部维护一个会话ID到对象实例的映射容器,每次获取对象时先根据会话ID查询容器,如果存在则返回已有实例,不存在则创建新实例并存入容器。
代码实现示例
import java.util.concurrent.ConcurrentHashMap;
// 会话对象接口
interface SessionObject {
String getSessionId();
void doBusiness();
}
// 会话对象实现类
class DefaultSessionObject implements SessionObject {
private String sessionId;
public DefaultSessionObject(String sessionId) {
this.sessionId = sessionId;
}
@Override
public String getSessionId() {
return sessionId;
}
@Override
public void doBusiness() {
System.out.println("会话" + sessionId + "执行业务逻辑");
}
}
// 对象工厂类
class SessionObjectFactory {
// 使用ConcurrentHashMap保证多线程下的容器安全
private static final ConcurrentHashMap<String, SessionObject> SESSION_OBJECT_MAP = new ConcurrentHashMap<>();
// 私有化构造方法,防止外部实例化工厂
private SessionObjectFactory() {}
// 根据会话ID获取唯一的对象实例
public static SessionObject getSessionObject(String sessionId) {
// 先查询容器中是否已有该会话的对象
SessionObject existObject = SESSION_OBJECT_MAP.get(sessionId);
if (existObject != null) {
return existObject;
}
// 不存在则创建新对象,使用putIfAbsent保证原子性,避免重复创建
SessionObject newObject = new DefaultSessionObject(sessionId);
SessionObject result = SESSION_OBJECT_MAP.putIfAbsent(sessionId, newObject);
return result == null ? newObject : result;
}
// 移除指定会话的对象,会话失效时调用
public static void removeSessionObject(String sessionId) {
SESSION_OBJECT_MAP.remove(sessionId);
}
}
使用示例
public class Test {
public static void main(String[] args) {
// 获取会话ID为user1的对象
SessionObject obj1 = SessionObjectFactory.getSessionObject("user1");
SessionObject obj2 = SessionObjectFactory.getSessionObject("user1");
// 输出true,说明两次获取的是同一个对象
System.out.println(obj1 == obj2);
// 获取不同会话ID的对象
SessionObject obj3 = SessionObjectFactory.getSessionObject("user2");
// 输出false,不同会话的对象不是同一个实例
System.out.println(obj1 == obj3);
}
}
两种方案的选择建议
如果只需要全局唯一的单个对象实例,优先选择单例模式,实现简单性能高;如果需要为不同的会话或者业务标识维护各自唯一的对象实例,工厂模式结合会话管理的方案更合适,扩展性更强。两种方案都可以在JVM层面保证对象的唯一性,开发者需要根据实际业务场景选择。