说说单例模式

来源:互联网 发布:java整形转换为字符串 编辑:程序博客网 时间:2024/06/09 13:02

单例模式应该都不陌生,被广泛使用的设计模式之一,在应用这个模式时,单例对象的类必须保证只有一个实例存在。

下面将会为大家介绍几种单例实现的方式,虽然实现方式有差异,但是核心原理都是:

1、将构造函数私有化

2、通过静态方法获取一个唯一的实例

3、在获取过程中保证线程安全

4、防止反序列化导致重新生成实例对象


线程不安全的单例

这种实现方式是线程不安全的,非常不推荐这种做法

public class Signleton {private  static Signleton signleton;private Signleton() {}/** * 第一中方式:缺点,多线程访问时不安全 *  * @return */public static Signleton getInstance() {if (signleton == null) {signleton = new Signleton();}return signleton;}/** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */private Object readResolve() throws ObjectStreamException {return signleton;}}

线程安全的单例

这种方式是线程安全的,但是每次访问getInstance()方法时都会进行同步控制,效率低

public class Signleton {private  static Signleton signleton;private Signleton() {}/** * 第二中方式 加上同步关键字,解决了多线程访问安全的问题 * 缺点:会降低性能,因为一旦设置好signleton变量,就不需要同步了,之后每次调用该方法会降低性能 *  * @return */public static synchronized Signleton getInstance() {if (signleton == null) {signleton = new Signleton();}return signleton;}/** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */private Object readResolve() throws ObjectStreamException {return signleton;}}

双重锁的单例模式

该方式避免了每次调用getInstance()方法都进行同步控制
public class Signleton {private  static Signleton signleton;private Signleton() {}/** * 第三种方式, 双重检查加锁,首先检查实例是否已经创建,如果未创建才进行同步控制, *  这样只有第一次会同步,提高了性能 *  * @return */public static Signleton getInstance() {if (signleton == null) {synchronized (Signleton.class) {if (signleton == null) {signleton = new Signleton();}}}return signleton;}/** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */private Object readResolve() throws ObjectStreamException {return signleton;}}
但是由于signleton=new Signleton()不是原子操作,由于线程调度的原因会在某些情况下出现失效的问题,不过只需要加上volatile即可(private volatile static Signleton signleton;)。

饿汉单例模式

该方式会在类加载时就初始化signleton。
public class Signleton { private static Signleton signleton=new Signleton();//对应第四中方式private Signleton() {} /** * 第四种方式,如果应用程序总是创建并使用单例实例,可以在镜头初始化器中创建单例, 使用时直接返回 * * @return */public static Signleton getInstance() {return signleton;}/** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */private Object readResolve() throws ObjectStreamException {return signleton;}}

静态内部类单例模式

该模式在类加载时不会初始化signleton,只有在调用get方法时才初始化

public class Signleton {/** * 第五种方式,使用静态内部类实现单例,相比饿汉模式不会在第一次加载Signleton类时就初始化sInstance, * 只有在调用getInstance时才会初始化 */public static Signleton getInstance() {return SignletonHolder.sInstance;}private static class SignletonHolder {private static final Signleton sInstance = new Signleton();}/** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */private Object readResolve() throws ObjectStreamException {return SignletonHolder.sInstance;}}



枚举单例

该方式写法简单,且默认枚举实例的创建时线程安全的,并且在任何情况下它都是一个单例

public enum SingletonEnum {INSTANCE;// TODO 一些类的方法public void doSomthing() {}}