单例模式的几种方式:饿汉式单例,懒汉单例,双层校验锁单例,容器单例,静态内部类单例,枚举单例。
饿汉单例
/**
* 饿汉单例(类加载的时候就获取实例)
* 线程安全的
*/
public class SingleTon {
private static SingleTon instance=new SingleTon();
private SingleTon(){
}
public static SingleTon getInstance(){
return instance;
}
}
懒汉单例
/**
* 懒汉单例(非线程安全)
*/
public class SingleTon {
private static SingleTon instance;
private SingleTon(){
}
public static SingleTon getInstance(){
if (instance==null){
instance=new SingleTon();
}
return instance;
}
}
/**
* 懒汉单例(线程安全)
*/
public class SingleTon {
private static SingleTon instance;
private SingleTon(){
}
public static synchronized SingleTon getInstance(){
if (instance==null){
instance=new SingleTon();
}
return instance;
}
}
在方法上加同步锁使得线程安全,但多线程访问方法每次都要等待锁的释放,这种方式性能太差。其实只需要在第一次实例化加锁就可以了,之后访问直接获取实例就好了。所以出现了双重检验锁单例模式。
双重校验锁单例
/**
* 双重检验锁单例(线程安全)
*/
public class SingleTon {
private static SingleTon instance;
private SingleTon(){
}
public static SingleTon getInstance(){
if (instance==null){
synchronized (SingleTon.class){
if (instance==null){
instance=new SingleTon();
}
}
}
return instance;
}
}
1.第一个if 判断是否已经实例化,如果实例化则直接返回,不需要在执行同步锁,优化了性能。
2.第二个 if,多个线程通过第一个 if判断,其中一个线程先获得锁并实例化对象,当第一个线程释放锁后,之后获得锁的线程不会在实例化对象,直接返回实例。
这种方式仍然存在隐患,对象实例化分三个步骤:
1.分配内存空间
2.初始化对象
3.将对象指向刚分配的内存空间
编译器为了性能可能将2和3的顺序重排序:
1.分配内存空间
2.将对象指向刚分配的内存空间
3.初始化对象
A线程执行到2步骤时instance 不为空,B线程判断到 instance 不为空,直接返回 instance,但是此时 instance 还未被初始化。使用volatile关键字解决问题,禁止重排,所有的写(write)操作都将发生在读(read)操作之前。
public class SingleTon {
private volatile static SingleTon instance;
private SingleTon(){
}
public static SingleTon getInstance(){
if (instance==null){
synchronized (SingleTon.class){
if (instance==null){
instance=new SingleTon();
}
}
}
return instance;
}
}
容器单例
/**
* 容器单例
*/
public class SingleTon {
private static Map<String,Object> objMap=new HashMap<>();
private SingleTon(){
}
public static void registerService(String key,Object instance){
if (!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
静态内部类单例
public class SingleTon {
private static class SingleTonHolder{
private static final SingleTon instance=new SingleTon();
private SingleTonHolder(){}
}
private SingleTon(){}
public static SingleTon getInstance(){
return SingleTonHolder.instance;
}
}
枚举单例
public enum SingleTon{
Singleton;
private SingleTon1 singleton;
//枚举类的构造方法在类加载是被实例化
private SingleTon(){
singleton = new SingleTon1();
}
public SingleTon1 getInstance(){
return singleton;
}
}
public class SingleTon1 {
public SingleTon1(){}
}