浅谈Java设计模式系列0x01---单例模式

浅谈Java设计模式系列0x00

上次我们对设计模式有了一些基本的了解,现在就从最简单最容易理解的单例模式开始吧;

什么是单例模式(Singleton)

这个模式看到名字就知道它是什么意思了,就是确保某个类只有一个实例,并且自动实例化和向全局提供该实例;
它是创建型模式;

适用场景

单例模式的使用场景比较多,我还是说说为什么会使用到单例模式吧;

  • 有的对象我们需要频繁的使用,但是使用完后它就被销毁,这样的情况下我们使用单例模式可以避免过多的创建和销毁步骤;
  • 有的对象我们创建时会耗费过多的时间和过多的资源,并且我们经常用到这个对象,这时使用单例模式就可以减少耗时和耗费资源的操作;

干说没什么意思,还是举些例子吧:

  1. 频繁访问数据库或网络或文件的对象;
  2. 有状态的工具类对象;

单例模式

说了这么多,还是代码最实际;
代码参考

1. 饿汉式

饿汉式是最简单的实现方法,这种方法在类加载的时候就实例化了,所以说这是饿汉式,简单粗暴;
这种方法在对象初始化速度较快,内存占用较少时适用;

1
2
3
4
5
6
7
8
9
10
public class Singleton {
//私有实例
private static Singleton instance = new Singleton();
//私有的构造函数
private Singleton(){}
//向外提供的全局访问方法
public static Singleton getInstance(){
return instance;
}
}

2. 懒汉式

懒汉式的实例化是延迟到需要时才进行;
当单例对象的初始化操作会耗费比较长的时间和比较多的资源时,采用懒汉式会是个不错的选择;

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
//私有实例
private static Singleton instance = null;
//私有构造函数
private Singleton() {}

public static Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}

3. 多线程下的单例模式

上面的两种方法在多线程的情况下,饿汉式是不会有问题的,因为JVM对类只加载一次,饿汉式只有在类加载时实例化;
但是懒汉式会出现重复创建实例的情况,因为懒汉式是线程不安全的;
下面是线程安全的懒汉式:

同步锁方式

这是一种比较常用的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton {
private static Singleton instance = null;

private Singleton() {}

public static Singleton getInstance() {
//使用同步锁防止多线程访问下,instance被多次实例化
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
return instance;
}
}

双层校验锁

这是上面的同步锁改进后的方法,性能会有所提高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private static Singleton instance = null;

private Singleton() {}

public static Singleton getInstance() {
//先检查instance是否被初始化,减少了获取对象同步锁的开销
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}

静态内部类

上面的方法都太麻烦了有木有,我们有简单的方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton{
private Singleton(){}
//静态内部类,当使用到内部类时才会进行加载,进行实例化
private static class SingletonHolder{
public static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}

public void doSomething(){
// do something....
}
}

枚举类型单例

静态内部类还不是最简单的实现方法,在 Effective Java 中提到了一种更简洁的方法,就是使用枚举;

1
2
3
4
5
6
7
public enum Singleton {
//这个就是单例模式的实例,它是一个枚举元素
instance;
public void doSomething(){
// do something
}
}

总结

上面的几种单例模式中,我们可以根据场景和需求选择使用,我个人就比较喜欢静态内部类的实现方法;
如果上面有什么理解错误的话,希望能帮忙指出;

参考

Android设计模式之单例模式
你真的会用单例模式吗