1.饿汉式html
public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){ … } public static Singleton getInstance(){ return instance; } }
缺点:第一次加载类的时候会连带着建立Singleton实例,这样的结果与咱们所指望的不一样,由于建立实例的时候可能并非咱们须要这个实例的时候。同时若是这个Singleton实例的建立很是消耗系统资源,而应用始终都没有使用Singleton实例,那么建立Singleton消耗的系统资源就被白白浪费了。安全
2.懒汉式多线程
public class Singleton{ private static Singleton instance = null; private Singleton(){ … } public static Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; } }
缺点:存在多线程并发问题,并发下可能建立多个对象。并发
3.解决并发问题函数
方法上使用Class锁机制线程
public static synchronized Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; }
缺点:加载方法上锁粒度太大,影响并发。实际上当单例实例被建立之后,其后的请求没有必要再使用互斥机制了。htm
用double-checked locking将锁缩减至代码块级别对象
public static Singleton getInstance(){ if (instance == null) synchronized(instance){ if(instance == null) instance = new Singleton(); } return instance; }
对于JVM而言,它执行的是一个个Java指令。在Java指令中建立对象和赋值操做是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。可是JVM并不保证这两个操做的前后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,而后直接赋值给instance成员,而后再去初始化这个Singleton实例。这样就使出错成为了可能。blog
使用volatile防止重排序:排序
public class Singleton{ private static volatile Singleton instance = null; private Singleton(){ … } public static Singleton getInstance(){ if (instance == null) synchronized(instance){ if(instance == null) instance = new Singleton(); } return instance; }
不加锁:为了实现慢加载,而且不但愿每次调用getInstance时都必须互斥执行。
public class Singleton{ private Singleton(){ … } private static class SingletonContainer{ private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonContainer.instance; } }
JVM内部的机制可以保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当咱们第一次调用getInstance的时候,JVM可以帮咱们保证instance只被建立一次,而且会保证把赋值给instance的内存初始化完毕,这样咱们就不用担忧3.2中的问题。此外该方法也只会在第一次调用的时候使用互斥机制,这样就解决了3.1中的低效问题。最后instance是在第一次加载SingletonContainer类时被建立的,而SingletonContainer类则在调用getInstance方法的时候才会被加载,所以也实现了惰性加载。
https://www.cnblogs.com/jingpeipei/p/5771716.html
/** 推荐
* 静态内部类实现单例模式(懒加载的一种)
* 静态内部类只有在调用的时候才初始化,而且初始化过程线程安全。
* instance不提供修改实例方法,静态变量只初始化一次,因此final修饰不加也同样。
* 兼备了并发高效调用和懒加载的优点。
* 结论:线程安全,调用效率高,而且能够延时加载。
*/
public class StaticClassSingleton {
//私有构造函数
private StaticClassSingleton(){};
//静态内部类
private static class SingletonClassInstance{
private static final StaticClassSingleton INSTANCE =
new StaticClassSingleton();
}
//提供实例的调用方法
public static StaticClassSingleton getInstance(){
return SingletonClassInstance.INSTANCE;
}
}
/** 推荐
* 枚举类对象自己就是一个单例对象。
* 没有延时加载的特性。
* 能够自然的防止反射和反序列化的漏洞,由于枚举是基于JVM底层实现的。
* 结论:线程安全,调用效率高,可是不是延时加载,自然防止反射和反序列化漏洞。
*/
public enum EnumSingleton {
/**
* 枚举对象
*/
INSTANCE;
/** * 成员方法 */ public void singletonOperation(){ //单例对象的其它操做实现。 } }