[关闭]
@XQF 2016-12-21T10:56:47.000000Z 字数 2338 阅读 1119

单例模式

java设计模式-----实验楼


Java设计模式----单例模式

什么是单例模式(Singleton Pattern):

就是被单例的对象只能有一个实例存在。单例模式的事项方式是:一个类只能返回对象的一个引用(永远是同一个)和一个获得该唯一实例的方法(必须是静态方法)通过单例模式,我们可以保证系统中只有一个实例,从而在某些特定的场合下达到节约或者控制系统资源的目的

单例模式类图

此处输入图片的描述

单例模式实例

单例模式有很多种的实现

饿汉模式

最常见的就是饿汉模式,最简单。一上来就是新建一个实例。但是这种方法有一个明显的缺点就是不管有没有获得过实例的方法,每次都会新建一个实例

  1. public class Wife {
  2. // 一开始就新建一个实例,这是自引用?
  3. private static final Wife wife = new Wife();
  4. // 默认的构造方法
  5. public Wife() {
  6. // TODO Auto-generated constructor stub
  7. }
  8. // 获得实例的方法
  9. public static Wife getWife() {
  10. return wife;
  11. }
  12. }

懒汉模式

最常见,最简单之二。就是开始的时候不创建实例,只有在需要使用的时候才创建实例,会先判断实例是否为空,如果为空才会新建一个实例来使用

  1. public class Wife {
  2. // 一开始没有新建一个实例
  3. private static Wife wife;
  4. // 默认的构造方法
  5. public Wife() {
  6. // TODO Auto-generated constructor stub
  7. }
  8. // 需要时才创建
  9. public static Wife getWife() {
  10. if (wife == null) {
  11. wife = new Wife();
  12. }
  13. return wife;
  14. }
  15. }

线程安全的懒汉模式

懒汉模式确实很简单,但是要注意的是上面的懒汉模式存在一个严重的问题。就是如果有多个线程并行使用getWife()方法的时候,还是会创建多个实例,单例模式就失效了。
于是我们在懒汉模式的基础上,把它设为线程同步。synchronized的作用就是保证在同一时刻最多只有一个线程运行,这样就避免了多线程带来的麻烦

  1. public class Wife {
  2. // 一开始没有新建一个实例
  3. private static Wife wife;
  4. // 默认的构造方法
  5. public Wife() {
  6. // TODO Auto-generated constructor stub
  7. }
  8. // 添加了关键字
  9. public static synchronized Wife getWife() {
  10. if (wife == null) {
  11. wife = new Wife();
  12. }
  13. return wife;
  14. }
  15. }

双重检验锁

线程安全的懒汉模式解决了多线程的问题,但那时效率并不高,每次调用获取实例的getWife()方法时都要进行同步,但是多数情况下是不需要进行同步操作的(比如在wife实例并不为空可以直接使用的时候,就不需要加同步方法,直接返回实例),所以只需要在第一次新建实例对象的时候使用同步方法

getWife()方法的双重检验锁
  1. public static Wife getWife() {
  2. if (wife == null) {//第一次为空的时候
  3. synchronized (Wife.class){//同步创建
  4. if (wife==null) {
  5. wife=new Wife();
  6. }
  7. }
  8. }
  9. return wife;
  10. }

注意这里并没有结束,主要问题在于wife=new Wife()因为在JVM执行这句代码的时候,要做好几件事情,而JVM为了优化代码,有可能造成做这几件事情的执行顺序是不固定的,从而造成错误。因此我们要阻止代码自行进行优,于是加上一个volatile关键字
```java
//双重检验锁的最终式
public class Wife {
// 一开始没有新建一个实例
private volatile static Wife wife;

// 默认的构造方法
public Wife() {
    // TODO Auto-generated constructor stub
}

// 需要时才创建
public static Wife getWife() {//第一次为空的时候
    if (wife == null) {
        synchronized (Wife.class){//同步创建
            if (wife==null) {
                wife=new Wife();
            }
        }
    }
    return wife;
}

}


#### 静态内部类
`volatile`关键字在老版本中JDK是无法正常工作的。这种静态内部类的方式,利用了JVM自身的机制来保证线程安全。因为`WifeHloder`是私有的,除了getWife()之外没有其他方式可以访问实例对象,而且只有在调用`getWife()`时才会真正创建实例对象
java

public class Wife {
private static class WifeHolder {
private static final Wife wife = new Wife();
}

private Wife() {

}

public static Wife getWife() {
    return WifeHolder.wife;
}

}


#### 枚举
代码很是简单,可以通过`Wife.INSTANCE`来访问对象,这比`getWife()`简单得多,而且创建枚举默认就是线程安全的,还可以防止反序列化带来的问题
java
public enum Wife {
INSTANCE;
// 自定义的其他任何方法
public void whateverMethod() {

}

}
```

单利模式的应用

当你只需要一个实例对象的时候,就可以考虑使用单例模式。比如在资源共享的情况下,避免由于多个资源操作导致的性能或损耗等,就可以使用单例模式。Config类里面就是使用的单例模式?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注