上次我们对设计模式有了一些基本的了解,现在就从最简单最容易理解的单例模式开始吧;
什么是单例模式(Singleton)
这个模式看到名字就知道它是什么意思了,就是确保某个类只有一个实例,并且自动实例化和向全局提供该实例;
它是创建型模式;
适用场景
单例模式的使用场景比较多,我还是说说为什么会使用到单例模式吧;
- 有的对象我们需要频繁的使用,但是使用完后它就被销毁,这样的情况下我们使用单例模式可以避免过多的创建和销毁步骤;
- 有的对象我们创建时会耗费过多的时间和过多的资源,并且我们经常用到这个对象,这时使用单例模式就可以减少耗时和耗费资源的操作;
干说没什么意思,还是举些例子吧:
- 频繁访问数据库或网络或文件的对象;
- 有状态的工具类对象;
…
单例模式
说了这么多,还是代码最实际;
代码参考
1. 饿汉式
饿汉式是最简单的实现方法,这种方法在类加载的时候就实例化了,所以说这是饿汉式,简单粗暴;
这种方法在对象初始化速度较快,内存占用较少时适用;1
2
3
4
5
6
7
8
9
10public 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
13public 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
15public 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
17public 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
14public 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
7public enum Singleton {
//这个就是单例模式的实例,它是一个枚举元素
instance;
public void doSomething(){
// do something
}
}
总结
上面的几种单例模式中,我们可以根据场景和需求选择使用,我个人就比较喜欢静态内部类的实现方法;
如果上面有什么理解错误的话,希望能帮忙指出;