Android中的单例模式
来源:互联网 发布:制造业大数据采集 编辑:程序博客网 时间:2024/05/16 15:23
单例模式在设计模式中是最方便人们理解的。虽然容易理解,但里面坑挺多的,所以在面试题中经常哪来做考题。简单来说,单例模式,就是为了保证类对象只有并且只能创建一个。规模比较大的类,或者需要反复使用的类,才会使用单例模式。下面一起探讨一下单例模式的几种方式。
懒汉式,线程不安全
当提到单例模式的时候,可能很多人会在第一时间想到如下的代码。
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
在这个方法中,其实代码非常的简单明了,但是其存在的问题就是,当多个线程并行调用上面的getInstance()时,就会创建多个实例,结果就是不能在多线程 下正常运行。
懒汉式,线程安全
为了解决上述的问题,其实很简单,只需要在getInstance()加一个同步锁(synchronized)就可以了.public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }如果多个线程进入,只允许进入一个,且执行完之后,才能允许另一个线程进入。
双重检验锁
双重检验锁,是一种使用同步块加锁的方法。因为会有两次if判断检查instance是否为空,一次是在同步块外,一次是在同步块内。
public static Singleton getSingleton() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance ; }
这段代码看起来很完美,不过有问题,主要是instance = newSingleton()这句,这并非一个原子操作,事实上在JVM中这句话大概做了下面三件事情。
1.给instance分配内存
2.调用Singleton的构造函数来初始化成员变量
3.将instance对象指向分配的内存空间(执行完这一步instance就非null了)
但是在JVM的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三部的顺序是不能保证的,最终的执行顺序可能是1-2-3,也可能是1-3-2.如果是后者,则在3执行完毕、2未执行之前,被线程二抢占了。这时instance已经是非null了(但却没有初始化),所以线程二会直接返回instance,然后使用,然后就GG报错了。
我们只需要把instance变量声明成volatile就可以了。
public class Singleton { private volatile static Singleton instance; //声明成 volatile private Singleton (){} public static Singleton getSingleton() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。它在某些情况下比synchronized的开销更小。
饿汉式 static final field
这种方法很简单,因为单利的实例被声明称static和final变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。
public class Singleton{ //类加载时就初始化 private static final Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }这种写法缺点是它不是一种懒汉式加载模式,单例会在加载类后一开始就被初始化,即时客户端没有调用getInstance()方法,饿汉式的创建方式在
一些场景中无法使用:譬如Singleton实例的创建时依赖参数或者配置文件的,在getInstance()之前必须调用某个方法设置参数给它,那样这种单例写
法就无法使用了。
静态内部类
个人倾向于静态内部类的方法。
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }这种写法仍然使用JVM本身机制保证了线程安全问题;由于SingletonHolder是私有的,除了getInstance之外没有办法访问它,因为它是懒汉式的;
同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖JDK版本。
枚举
这种方法很简单,也是它最大的优点了。
public enum EasySingleton{ INSTANCE; }
-ng而且还能防止反序列化导致重新创建新的对象。这种方法很少看到有人写,大概是因为不熟悉。
总结
一般来说,单例模式一般分为5种写法:懒汉式、饿汉式、双重检验锁、静态内部类、枚举。上述所说多事线程安全的实现,开头中的第一种方法不
算正确的写法。正常情况下没直接使用饿汉式就好了,如果明确要求要懒汉式会倾向于静态内部类,如果涉及到反序列化创建对象时会试着使用枚举方
式来实现单例。
1 0
- Android中的单例模式
- Android 中的单例模式
- android中的单例模式
- android中的单例模式
- Android中的设计模式-单例模式
- Android开发中的单例模式
- 单例模式在android中的应用
- 读书笔记--android中的单例模式
- Android源码中的单例模式
- Android中的单例模式使用场景
- android 源码中的单例模式
- Android源码中的单例模式
- android源码中的单例模式实现
- Android中的单例设计模式
- 单例模式在Android中的应用
- Android中的单例模式详解
- Android中的单任务模式
- 单利模式android,java中的单例模式。简单讲解单例模式
- 金币阵列问题
- view & data
- Qt Creator 使用技巧之提高编译速度【使用jom参数】
- 算法--java(1)
- 复习:卡方检验
- Android中的单例模式
- android service 分析的比较好。
- Java - 内部类
- win10 tomcat8 jsp报500错误,java.lang.classNotFoundException
- 加速Android Studio的Gradle构建速度
- 模糊加法、模糊乘法算法牛刀小试
- 关于重装系统后Eclipse+ADT或者AndroidStudio真机测试检测不到真机的解决
- Installation error: INSTALL_FAILED_MEDIA_UNAVAILABLE
- 【洛谷 1032】 字串变换