HeadFirst:设计模式-单例模式

1.单例模式(Singleleton Pattern)

  • 模式介绍

单例模式是非常常见的设计模式,有一些对象,我们只需要一个,比如下面这些使用场景:

线程池(threadpool)、缓存(cache)、日志对象等

  • 模式定义

单例模式:

确保一个类只有一个实例,并提供一个全局访问点。

单例模式要求只能有一个实例,所以它的构造方法是私有的方法,及private类型的构造方法。构造方法是私有类型,只能在该类中创建实例。所以单例模式提供一个静态方法去创建一个对象。

2.基本实现思路

单例模式要求类能够有返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称)。

单例的实现主要是通过以下两个步骤:

  1. 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
  2. 在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。

3.单例模式的几种实现

1、饿汉式(静态常量)[可用]

public class Singleton {

    private  static final Singleton INSTANCE = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return INSTANCE;
    }
}

最简单的方式,在类加载时完成初始化,没有达到懒加载的方式,但避免了多线程同步的问题。 

2、饿汉式(静态代码块)[可用]

public class Singleton {

    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    private Singleton() {}

    public Singleton getInstance() {
        return instance;
    }
}

与上面的类似,只是类实例化放在了静态块中,。

3、懒汉式(线程不安全)[不可用]

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

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

达到了懒加载的功能,但只能在单线程下使用,多线程下存在同步问题,可能会创建多个对象,出现错误。

 4、懒汉式(线程安全,同步方法)[不推荐用]

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

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

在方法上使用synchronized关键字解决了多线程下,出错的问题, 但执行效率下降,每一次获取单例都要执行同步方法,实际只有第一次需要不同,后面直接返回实例即可,不推荐使用,需要改进。

5、懒汉式(线程安全,同步代码块)[不可用]

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

使用同步块,不能解决多线程同步问题,也可能会创建多个实例,多线程下不可用。 

6、双重检查[推荐用]

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

两次判断,保证了多线程下安全访问。 

7、静态内部类[推荐用]

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

优点:避免了线程不安全,延迟加载,效率高。

 8、枚举[推荐用]

public enum Singleton {

    INSTANCE;
    
    private String str;

    Singleton(){
        str = "hello singleton pattern";
   }

    public String getInstance() {
        return this.str;
    }
}

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

枚举中的变量是静态变量,方法是静态方法,即类变量,类方法。枚举中的 构造方法是私有的构造方法。

使用时调用: Singleton.INSTANCE.getInstance()可以获取到单例。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值