单例模式应该是涉及学习的较早的模式之一了,俗话说,麻雀虽小......呸呸呸,话又多了
先来个大纲,对于java而言,你也是单例只有两种。吓死你,回字的四种写法。
1 饿汉模式(加载类时比较慢,但获取对象时快)
2 懒汉模式(加载类时快,运行获取对象慢)
3 通过java加载类时先加载静态{static}资源的手段(歪门邪道)
4 通过枚举(奇巧淫技)
-----------------------------------------------------------------------------
1 饿汉模式大概这样,不多说
public class SingletonHungry {
private SingletonHungry() {
}
private static SingletonHungry instance = new SingletonHungry();
public static SingletonHungry getSingleton() {
return instance;
}
}
---------------------------------------------------------
懒汉模式的初级样子
public class SingletonLazy {
private SingletonLazy() {
}
private static SingletonLazy instance = null;
public static SingletonLazy getSingleton() {
if(instance ==null){
instance =new SingletonLazy();
}
return instance;
}
}
这种模式在单线程下是玩的很high的,但是多线程就扑街了。
所以,懒汉模式进化 --》 synchronized懒汉模式
public class SingletonLazy {
private SingletonLazy() {
}
private static SingletonLazy instance = null;
public static synchronized SingletonLazy getSingleton() {
if(instance ==null){
instance =new SingletonLazy();
}
return instance;
}
}
多线程是安全,但是每次获得对象都需要走一次synchronized这个重量级锁,影响效率啊
懒汉模式进化 ---》》 双重判断懒汉模式
public class SingletonLazy {
private SingletonLazy() {
}
private static SingletonLazy instance = null;
public static SingletonLazy getSingleton() {
if(instance ==null){
synchronized(SingletonLazy.class){
if(instance==null){
instance =new SingletonLazy();
}
}
}
return instance;
}
}
但是如果你运气足够好,这种模式下并发还是可能出问题。大概解释是,因为指令重排序的关系,比如三部曲
(1)分配内存空间。
(2)初始化对象。
(3)将内存空间的地址赋值给对应的引用。
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:
(1)分配内存空间。
(2)将内存空间的地址赋值给对应的引用。
(3)初始化对象
最后懒汉模式究极进化 ,上volatile的懒汉模式
public class SingletonLazy {
private SingletonLazy() {
}
private static volatile SingletonLazy instance = null;
public static SingletonLazy getSingleton() {
if(instance ==null){
synchronized(SingletonLazy.class){
if(instance==null){
instance =new SingletonLazy();
}
}
}
return instance;
}
}
虽然说这个是单例模式不能new出来,但是实际上能够通过反射给弄个新对象。
不过如果是枚举的单例就不能通过反射弄一个新的。暂时不讨论这个花式摸鱼。
总结: 单例模式,还是饿汉模式好用........