单例模式特点
1、单例模式是用来实现在整个程序中只有一个实例的。
2、单例类的构造函数必须为私有,同时单例类必须提供一个全局访问点。
有哪些实现方式?
synchronized同步锁的方式导致性能低下,考虑以下实现方式:
1、静态内部类,常用的简单实现方式,既保证了安全又实现了懒加载
2、饿汉式,应用启动时初始化实例对象
3、懒汉式,为了支持懒加载而设计,通过synchronized来实现
4、双重检测,懒汉式有性能问题
5、枚举
//饿汉式
public class Singleton {
private static final Singleton singleton = new Singleton();
//私有的构造函数
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
//懒汉式
public class Singleton {
private static Singleton singleton;
//私有的构造函数
private Singleton() {}
public static synchronized Singleton getInstance() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
//双重锁定方式
public class Singleton {
private static Singleton singleton;
//私有的构造函数
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
sychronized(Singleton.class) {//这里是关键,一定是类级别的锁
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类方式来实现
public class Manager {
private Manager() {}
public static Manager getInstance() {
return ManagerHolder.instance;
}
private static class ManagerHolder {
private static final Manager instance = new Manager();
}
}
再来一例
public class JobQueue<T> {
private LoanTask task;
private JobQueue(LoanTask task){
super();
this.task = task;
}
/**
* 用户相关处理:注册开户,绑定银行卡等
* @return
*/
public static JobQueue <ValueEvent> getUserInstance() {
return LazyHolder.USER_INSTANCE;
}
//静态内部类
private static class LazyHolder {
// 用户相关队列
private static final JobQueue <ValueEvent> USER_INSTANCE = new JobQueue<ValueEvent>(new UserTask());
}
}
为什么要用这种静态内部类方式?
1、内部类只在需要的时候才会被类加载器加载,实现了懒加载;
2、由于instance是static 类型,保证了内存中只有这样一个实例存在;
3、final 只能被赋值一次,从而保证了线程安全性(即使在高并发情况下多线程同时调用getInstance()方法,也能保证实例的唯一性);
//利用AtomicLong的安全特性,java语言特有的实现方式
public enum IdGenerator {
INSTANCE;
private AtomicLong id = new AtomicLong(0);
public long getId() {
return id.incrementAndGet();
}
}
拓展思考
实际场景下,单例模式又可以按情况分为:线程单例、进程单例和集群单例。
线程单例:如web一次会话session,ThreadLoacal可以实现,ThreadLocal的使用
进程单例:在一个jvm内的单例
集群单例:雪花算法生成唯一Id