这里对java中的单例模式进行一些简单的描述,并不对其进行过于深入的探讨,比如现在有一些帖子中有认为使用枚举创建的单例模式,是一个很简单,而又特别高效的实现方式;另外通过使用内部类也可以实现不错的单例模式的效果,这里只对四种常见的实现方式进行简单的比较讨论(更深入的探讨可以看这里enum implement singleton 和 java单例真的写对了吗?)
首先是用两种不同的加载方式的代码实现,代码如下
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance==null) {
instance=new Singleton();}
return instance;}
}
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){return instance;}
}
第一种方式即所谓的懒加载比第二种方式在加载的时候效率要高些,缺点是如果使用多线程的话没有第二种方法安全,第一种实现方式在执行if(instance==null){}时如果是多线程的同时执行到了这里,将会有创建两个实例的危险,而第二种实现方式则没有这样的顾虑,但是这两种方法相对于接下来要描述的两种实现方式都显得相对有点简单且不够专业。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();}
return instance;}
}
、、、public class Singleton {
private volatile static Singleton instance;
privateSingleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
instance=newSingleton();}
}
return instance;}
}
第三种实现方式只是在第一种实现方式的基础上添加了异步锁,这样做的目的是让该类在多线程的状况下运行时保证是只创建一个实例的,但是这个方法在运行的时候,需要每次执行getInstance方法的时候,整个方法都是要保证线程安全的,这会严重影响多线程的效率,相对而言,第四种方法就压优雅和高效了很多,首先,只有该类在第一次获取实例的时候会执行一次创建实例的同步代码,之后将不再需要执行加锁的代码,效率是明显有了提高的,这种单例的写法被称之为“双重检查加锁”。而volatile关键字的添加同样是为了线程安全着想,即使是加了双重加锁,在一定的条件下,依然有可能会出现意外的情况,详细的可以查看上面介绍的两个链接,这里不做深入的探讨
以上就是比较常见的四种单例模式的写法
在Android的开发中很多人都知道,为了保证一个对象或者变量能够有一个比较长的生命周期,我们会将很多实例和参数写在Application类下面,这也可以变相的实现整个项目中我们所需要的某个实例对象是单例的,但是这两种实现方式有一个很明显的区别,在google讲解volley(网络图片请求框架)的使用的时候建议RequestQueue写成单例的模式,而不是创建一个实例对象放在application下面。这样建议的原因是因为单例的写法更符合面向对象的思维,更易于移植封装。
水平有限,纯手打,错误地方欢迎纠正。