保证一个类仅有一个实例,并提供一个访问它的全局访问点。
动机 适用性需要确保一个类的实例必须全局唯一,并且可以全局访问。
结构 优点- 对唯一实例的受控访问。
- 缩小名空间,可以避免那些存储唯一实例的全局变量污染名空间。
public class Singleton01 {
private static Singleton01 singleton = null;
private Singleton01(){
}
public static Singleton01 getInstance(){
if(singleton == null ){
singleton = new Singleton01();
}
return singleton;
}
}
饿汉式(线程安全)
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式(线程安全)
public class Singleton01 {
private static Singleton01 singleton = null;
private Singleton01(){
}
public static synchronized Singleton01 getInstance(){
if(singleton == null ){
singleton = new Singleton01();
}
return singleton;
}
}
懒汉式–双重校验锁(线程安全)
public class Singleton02 {
private volatile static Singleton02 singleton = null;
private Singleton02(){ }
public static Singleton02 getInstance(){
//加锁前检测
if(singleton == null ){
synchronized (Singleton02.class){
//加锁后检测
if(singleton == null){
singleton = new Singleton02();
}
}
}
return singleton;
}
}
单层锁为什么不行?
if (singleton == null) {
synchronized (Singleton02.class) {
singleton = new Singleton02();
}
}
假如两个线程同时执行了if (singleton == null)语句,并且都通过了if检测,即使if语句里面有synchronized锁, singleton = new Singleton02()依然会被两个线程分别执行一次,因为假如第一个先进入同步代码块执行,第二个线程等待,当第一个执行结束,第二个依然可以获得锁去执行。
静态内部类实现利用静态内部类仅在类初始化的时候加载一次的性质。该实现也属于懒汉式,因为刚Singleton初始化的时候private static final Singleton INSTANCE = new Singleton()并不会执行,只有调用getUniqueInstance方法的时候才会执行。
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举实现(重要)
这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。
public enum Singleton{
uniqueInstance;
private Singleton(){
System.out.println("here");
}
public void doSomething(){
System.out.println("hello");
}
public static void main(String[] args) {
//在此执行了私有方法,也即执行new Singleton()的地方
Singleton uniqueInstance = Singleton.uniqueInstance;
// Singleton uniqueInstance2 = Singleton.uniqueInstance;
// System.out.println(uniqueInstance.equals(uniqueInstance2)); true
//调用一些方法
uniqueInstance.doSomething();
}
}



