1. 什么是单例设计模式
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一一个实例
- 单例类必须给所有其他对象提供这一实例
2. 懒汉式单例
- 特点:在第一次调用的时候实例化自己
public class Singleton{
private Singleton(){}
private static Singleton single = null;
//静态工厂方法
public static Singleton getInstance(){
if (single == null){
single = new Singleton();
}
return single;
}
2.1存在的问题
- 通过反射机制是能够实例化构造方法为private的类的,那基本上所有使用java单例都会失效。
- 没有考虑线程安全,下面是改造方式
2.2 决断线程安全问题
2.2.1 在getInstance方法上机上同步
public static synchronized Singleton getInstance(){
if(single == null){
single = new Singleton();
}
return single;
}
2.2.2 同步代码块
public static Singleton getInstance(){
if(singleton == null){
sychronized(Singleton.class){
if(singleton == null)({
singleton = new Singleton();
}
}
}
return singleton;
}
2.2.3 静态内部类
public class Singleton{
private Singleton(){}
private static class LazyHolder{
//final修饰的变量只能被赋值一次
private static final Singleton INSTANCE = new Singleton();
}
//final修饰的方法不能够被重写,但是可以被继承
public static final Singleton getInstance(){
return LazyHolder.INSTANCE;
}
}
// final修饰的类不能被继承
- 似乎这种方式比较优雅
至于1、2、3这三种实现又有些区别,
第1种,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的,
第2种,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗
第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。
————————————————
2. 饿汉式单例(天生就是线程安全的)
- 特点:饿汉式单例,在类初始化时,就已经自行实例化
public class Singleton1{
private Singleton1(){}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance(){
return single;
}
}
参考:
原文链接:https://blog.csdn.net/jason0539/article/details/23297037