如何实现一个单例
- 构造函数需要是 private 访问权限,这样才能避免外部通过 new 创建实例;
- 考虑对象创建时的线程安全问题;
- 考虑是否支持延迟加载
- 考虑 getInstance() 性能是否高(是否回锁)。
- 反序列化(可选)
单例写法
0. 懒汉式
public class Singleton {private static Singleton = new Singleton();private Singleton() {}}
1. 双重检查优化版(线程安全**)
- 优点: 使用的时候才会创建对象,不会造成各种资源 的浪费,线程安全。
缺点: 最优方案。
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}
2. 枚举单例 (推荐*)
- 优点: 使用的时候才会创建对象,不会造成各种资源 的浪费,线程安全。能防反序列化。(effect java)
缺点: 最优方案。
public class Singleton {private Singleton() {}private enum SingletonEnum {SINGLETON;private Singleton singleton;SingletonEnum() {singleton = new Singleton();}private Singleton getInstance() {return singleton;}}public Singleton getInstance() {return SingletonEnum.SINGLETON.getInstance();}}
3. 静态内部类方式(*)
- 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题,线程安全。
- 缺点:没有太大缺点。
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private static Singleton getInstance() {return SingletonHolder.INSTANCE;}}
4. 懒汉式改造(线程安全 **)
- 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。
缺点:没有线程安全问题,但是有很大的性能问题,当多个线程同时到达getInstance()方法时,需要排队进入。
public class Singleton {private static Singleton instance;private Singleton() {}public synchronized static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}
为什么要使用单例 ?
一、处理资源访问冲突
public class Logger {private FileWriter writer;public Logger(){File file = new File("/Users/cxw/log.txt");writer = new FileWriter(file, true);//true表示追加写入}public void log(String message) {writer.write(message);}}public class UserController {private Logger logger = new Logger();public void login(String username,String password) {//logger.log(username + " logined!");}}public class OrderController {private Logger logger = new Logger();public void create(OrderVo order) {//logger.log("Created an order: " + order.toString());}}
日志互相覆盖的问题
使用锁的方式,虽然能解决问题,但性能有问题
public class Logger {private FileWriter writer;public Logger() {File file = new File("/User/cxw/log.txt");writer = new FileWriter(file,true);//}public void log(String message) {synchronized(Logger.class) {writer.write(message);}}}
public class Logger {private FileWriter writer;private static final Logger instance = new Logger();private Logger() {File file = new File("/User/cxw/log.txt");writer = new FileWriter(file,true);//}public static Logger getInstance() {return instance;}}
二、表示全局唯一类
import java.util.concurrent.atomic.AtomicLong;public class IdGenerator {private AtomicLong id = new AtomicLong(1);private static final IdGenerator instance = new IdGenerator();private IdGenerator() {}public static IdGenerator getInstance() {return instance;}public long getId() {return id.incrementAndGet();}}// IdGenerator使用举例long id = IdGenerator.getInstance().getId();
单例存在哪些问题?
单例存在的问题
- 对OOP特性的支持不友好
- 单例会隐藏类之间的依赖关系
- 对代码的扩展性不友好
- 单例对代码的可测试性不友好
- 单例不支持有参数的构造函数
有何替代解决方案
如何设计实现一个集群环境下的分布式单例模式?
- 如何理解单例模式中的唯一性?
- 如何实现线程唯一的单例?
- 如何实现集群环境下的单例?
- 如何实现一个多例模式?
