其实想要写这篇博客的目的是为了缅怀下我所踩过的坑。最开始做android项目的时候,想做一个listview的全局刷新,通俗点说就是一个activity调用另一个activity中的方法。然后懵懵懂懂就用了static,觉得真特么是好用,所以也算是单例模式的启蒙吧。然后进公司,觉得公共静态变量真好用,搞个公共静态变量的类,然后不断地存储数据,现在知道了,在跨进程调度的过程中公共静态变量类往往会靠不住,然后你需要在全局Application中定义你必须跨进程调度的变量。而在实际开发中,公共静态变量的定位往往与final结合起来,作为程序的全局标识。我去,跑偏了。。。单例模式。。。
一、什么是设计模式呢?
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。就是你的前辈在编程的时候,总结开发经验,抽取出来比较好的程序结构模式。
二、单例模式
单例模式是为了保证整个应用中有且只有一个实例。比较好理解的是,假如你定义了一个公共类,需要被反复调用里面的方法,那么可能出现的问题就是你同时在两个地方实例化了这个方法后,可能会导致方法先后修改的不可控性,为什么用可能,因为,你完全可以用synchronized或者static关键字进行规避。就算你这么做了,你只是实现了功能,并没有真正考虑到性能问题,这么的new一个对象,就为了调用里面的方法,会开辟大量的内存空间,造成内存的浪费。所以单例模式是在开发中用的最多的一种设计模式。
三、常见的单例模式写法
1、最常见的饿汉式
public class Singleton1 {
/**
* 饿汉式
* 优点:在类加载的时候就完成了实例化,避免了线程的同步问题。缺点: 由于在类加载的时候就实例化了,所以没有达到Lazy
* Loading(懒加载)的效果,也就是说可能我没有用到这个实例,但是它也会加载,会造成内存的浪费
*/
private static Singleton1 instance = new Singleton1();
private Singleton1() {
};
public static Singleton1 getInstance() {
return instance;
}
}
2、懒汉式炮灰1.0
public class Singleton2 {
/**
* 单例模式的懒汉式
*
* 线程不安全,不可用 多个线程调用此方法, 可能第一个线程还没执行new方法的时候,第二个线程已经进入判断方法了,线程不安全
*/
private static Singleton2 instance = null;
// 构造方法
private Singleton2() {
}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
3、懒汉式炮灰2.0
public class Singleton3 {
/**
* 懒汉式线程安全的
*
* 线程安全,效率低不推荐使用,进行同步操作的时候假如instance!=null只需要直接return的话就亏大了
*/
private Singleton3() {
}
private static Singleton3 instance = null;
public static synchronized Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
4、懒汉式变种兵,锁住我想坚持的,return你想return的(装逼利器)
public class Singleton4 {
/**
* 懒汉式变种,属于懒汉式中最好的写法,保证了:延迟加载和线程安全
*/
private static Singleton4 instance=null;
private Singleton4() {};
public static Singleton4 getInstance(){
if (instance == null) {
synchronized (Singleton4.class) {
if (instance == null) {
instance = new Singleton4();
}
}
}
return instance;
}
}
5、使用一个持有类的方式
public class Singleton5 {
/**
* 使用一个持有类的方式,主要是为了不在类加载的时候初始化
*/
private Singleton5() {
};
private static class SingletonHolder {
private static Singleton5 instance = new Singleton5();
}
public static Singleton5 getInstance() {
return SingletonHolder.instance;
}
}
6、使用java的枚举
public enum Singleton6 {
/**
* java中的枚举,需要jdk1.5以上才能支持,主要是1.5才有的枚举
*/
instance;
private Singleton6() {
}
// 你想要调用的方法
public void sth() {
}
}
都推荐使用,除了炮灰版。第1种(饿汉式)最常见,但是会在加载的时候初始化,其他的几种3(懒汉式加锁判断)、5(持有类)、6(枚举)都是推荐使用的。
三、Android在什么场景下会使用单例模式?
目前我碰到的就是用户登录成功在初始化slidingmenu(侧滑页),用户头像用户信息,会在每次与服务器交互的时候提交token,也就是秘钥,如果秘钥失效,则需要提示用户下线操作,需要调用slidingmenu里面的注销头像的方法。so 就是这样。。。
还有就是需要频繁调用Application类中的公共方法
private static SysApplication instance;
//构造方法
private SysApplication(){}
//实例化一次
public static SysApplication getInstance(){
if (null == instance) {
synchronized (SysApplication.class) {
if(null==instance){
instance = new SysApplication();
}
}
}
return instance;
}
四、总结:
当这个类的对象需要在多个地方重复创建,需要调用这个类的内部方法,创建了多个实例造成内存资源的浪费或者多个实例由于多次调用容易导致结果出现错误(容易造成线程不安全),我们需要想到使用单例模式,而使用单例模式能够保证整个应用中有且只有一个实例,内部方法最多初始化一次。我觉得单例模式是一个很好的解决方式,因为类与类之间的方法调度是不可避免的。。。