浅谈java中单例的几种写法
2017-11-01 18:30
387 查看
开发中或多或少都会用到单例模式,写法有很多种,这里收集整理了下:
1、懒汉式:
1)把构造方法定义成private的,不让外面new的方式生成实例;
2)提供一个static方法供外部调用,在这个方法里面返回实例;
只有在需要的时候,调用getInstance()方法才创建实例;
2、饿汉式
第一次调用的时候先生成实例,在通过getInstances()方法返回,是一种线程安全的写法;
3、线程安全(synchronized)
懒汉式有个缺陷,就是无法处理并发的情况,试想有这样一个场景:
A线程第一次调用getInstance()获取一个实例,singleInstance为空,创建一个实例;
B线程第一次调用getInstance(),如果此时实例还未创建,singleInstance为空,就会在创建一个实例;
这样就会生成两个实例,修改下懒汉式的写法:
在方法面前加上synchronized 同步锁保证线程安全。
4、双重检验锁
上面的写法优化一下,可以改写成这样:
多了一个判断,是不是看起来比上面那种写法逼格更高了;好吧这里简单解释下:
当有多线程调用getInstance()的时候,先判断实例是否为空,如果不为空则直接返回,没后面什么事了;
如果为空则进入synchronized 语句块,下面过程就和上面写法一样了;
至于volatile关键字是让在编译的时候按顺序执行。
5、静态内部类的方式
上面的饿汉式也有个弊端,如果我需要在外部调用SingleInstance的一个全局变量,在类加载时,会先初始化生成实例,这好像并不是我们想要的,好吧,那就换一种写法:
这样就只在调用getInstance()方法的时候才去实例化。
6、反序列化的方式
这种写法是避免别人通过反射的方式来获取实例:
实现Serializable接口,增加readResolve()方法,这里复制一波解释吧:”反序列化机制:在反序列化的时候会判断如果实现了serializable 或者 externalizable接口的类中又包含readResolve()方法的话,会直接调用readResolve()方法来获取实例。”
7、枚举方式
通过反序列化的方式只是避免别人通过反射的方式获取实例,但并不能彻底阻止;
因为枚举的特点,只会有一个实例,同时保证了线程安全、反射安全和反序列化安全。
以上总结基本就这些了,其中3、4可以看做是懒汉式的衍生体吧,5可以看做是饿汉式的衍生体;具体使用哪个自己考量了吧,我个人用的多的还是4和5,如果获取实例的时候需要传值选用第四种。
1、懒汉式:
1)把构造方法定义成private的,不让外面new的方式生成实例;
2)提供一个static方法供外部调用,在这个方法里面返回实例;
public class SingleInstance { private static SingleInstance singleInstance; private SingleInstance() { } public static SingleInstance getInstance(){ if (null == singleInstance){ singleInstance = new SingleInstance(); } return singleInstance; } }
只有在需要的时候,调用getInstance()方法才创建实例;
2、饿汉式
第一次调用的时候先生成实例,在通过getInstances()方法返回,是一种线程安全的写法;
public class SingleInstance { private static final SingleInstance INSTANCE = new SingleInstance(); private SingleInstance() { } public static SingleInstance getInstance(){ return INSTANCE; } }
3、线程安全(synchronized)
懒汉式有个缺陷,就是无法处理并发的情况,试想有这样一个场景:
A线程第一次调用getInstance()获取一个实例,singleInstance为空,创建一个实例;
B线程第一次调用getInstance(),如果此时实例还未创建,singleInstance为空,就会在创建一个实例;
这样就会生成两个实例,修改下懒汉式的写法:
public class SingleInstance { private static SingleInstance singleInstance; private SingleInstance() { } public synchronized static SingleInstance getInstance(){ if (null == singleInstance){ singleInstance = new SingleInstance(); } return singleInstance; } }
在方法面前加上synchronized 同步锁保证线程安全。
4、双重检验锁
上面的写法优化一下,可以改写成这样:
public class SingleInstance { private static volatile SingleInstance singleInstance; private SingleInstance() { } public static SingleInstance getInstance(){ if (null == singleInstance){ synchronized (SingleInstance.class){ if (null == singleInstance){ singleInstance = new SingleInstance(); } } } return singleInstance; } }
多了一个判断,是不是看起来比上面那种写法逼格更高了;好吧这里简单解释下:
当有多线程调用getInstance()的时候,先判断实例是否为空,如果不为空则直接返回,没后面什么事了;
如果为空则进入synchronized 语句块,下面过程就和上面写法一样了;
至于volatile关键字是让在编译的时候按顺序执行。
5、静态内部类的方式
上面的饿汉式也有个弊端,如果我需要在外部调用SingleInstance的一个全局变量,在类加载时,会先初始化生成实例,这好像并不是我们想要的,好吧,那就换一种写法:
public class SingleInstance { private SingleInstance() { } private static class SingleHolder{ private static final SingleInstance INSTANCE = new SingleInstance(); } public static SingleInstance getInstance(){ return SingleHolder.INSTANCE; } }
这样就只在调用getInstance()方法的时候才去实例化。
6、反序列化的方式
这种写法是避免别人通过反射的方式来获取实例:
public class SingleInstance implements Serializable{ private SingleInstance() { } private static class SingleHolder{ private static final SingleInstance INSTANCE = new SingleInstance(); } public static SingleInstance getInstance(){ return SingleHolder.INSTANCE; } private Object readResolve(){ return SingleHolder.INSTANCE; } }
实现Serializable接口,增加readResolve()方法,这里复制一波解释吧:”反序列化机制:在反序列化的时候会判断如果实现了serializable 或者 externalizable接口的类中又包含readResolve()方法的话,会直接调用readResolve()方法来获取实例。”
7、枚举方式
通过反序列化的方式只是避免别人通过反射的方式获取实例,但并不能彻底阻止;
public enum SingleInstance{ INSTANCE; //... ... }
因为枚举的特点,只会有一个实例,同时保证了线程安全、反射安全和反序列化安全。
以上总结基本就这些了,其中3、4可以看做是懒汉式的衍生体吧,5可以看做是饿汉式的衍生体;具体使用哪个自己考量了吧,我个人用的多的还是4和5,如果获取实例的时候需要传值选用第四种。
相关文章推荐
- java中单例模式的几种写法
- java中单例的几种写法
- 单例模式java中的几种写法和确保多线程下安全
- JAVA for循环的几种写法。
- 关于java中的main方法的几种写法
- Java中单例七种写法(懒汉、恶汉、静态内部类、双重检验锁、枚举)
- Java多线程编程-单例模式几种写法的错与对
- 浅谈Java中的几种随机数
- Java Web开发5___jQuery 中 按钮点击事件的几种写法
- 浅谈JAVA中几种循环语句的区别
- 浅谈Java中的几种随机数
- java设计模式之单例模式(几种写法及比较)
- 浅谈Java中的几种随机数
- 单例模式java中的几种写法和确保多线程下安全
- 浅谈Java中的几种随机数
- Java多线程编程-单例模式几种写法的错与对
- 浅谈Java中的几种随机数
- 浅谈JAVA中几种循环语句的区别
- 回字有几种写法?看Java里面让初学者迷惑的东西
- java中for循环的几种写法