Java单例模式几种实现方式

       在平时的工作、学员的学习以及面试过程中,单例模式作为一种常用的设计模式,会经常被面试官问到,甚至笔试会要求学员现场默写,下面将会就单例模式的实现思路和几种常见的实现方式进行简单的分享。

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。是最常用到的设计模式之一,熟悉设计模式的朋友对单例模式都不会陌生。一般介绍单例模式的书籍都会提到 饿汉式  懒汉式 这两种实现方式。但是除了这两种方式,本文还会介绍其他几种实现单例的方式。

基本的实现思路

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

通俗的讲:即设计一个类,在整个应用中只存在一个对象(需要做到让本类的外部不能够随意创建对象)

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

① 构造方法私有化(暂时不考虑反射)

② 在内部创建好一个对象并保存起来

③ 向外提供一个公共的静态的方法,返回内部对象的地址

第一种实现方式:饿汉[静态常量]的方式

示例代码:

扫描二维码关注公众号,回复: 54652 查看本文章

package cn.itsource.sington;

/**

 * 饿汉式[静态常量]

 *

 * @author Administrator

 *

 */

public class SingletonTest1 {

/**

 * 单例模式 设计一个类 ,让这个 类中只存在一个对象的实例

 *

 * 1 需要一个私有的 构造方法,这样可以避免外部创建对象

 */

private SingletonTest1() {

}

/*

 * 2 在本类内部创建一个 对象 ,保存起来

 */

private static SingletonTest1 instance = new SingletonTest1();

/*

 * 3 向外公布一个 公共的 静态的方法 ,返回内部保存的这个对象

 *

 */

public static SingletonTest1 getInstance() {

return instance;

}

}

优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

缺点:对象的创建是类加载的时候,可能会导致类加载很慢,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

第二种实现方式:饿汉式[静态代码块]的方式

示例代码:

package cn.itsource.sington;

public class SingletonTest3 {

private SingletonTest3() {

}

private static SingletonTest3 instance;

static {

instance = new SingletonTest3();

}

public static SingletonTest3 getInstance() {

return instance;

}

}

这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。

第三种实现方式:懒汉式[双重检查]的方式

示例代码:

package cn.itsource.sington;

/**

 * 懒汉式

 * @author Administrator

 */

public class SingletonTest2 {

/**

 * 需求:单例模式 设计一个类 ,让这个 类中只存在一个对象的实例

 *

 * 1 需要一个私有的 构造方法,这样可以避免外部创建对象

 */

private SingletonTest2() {

}

/*

 * 2 类加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,对

象才开始创建

 */

private static SingletonTest2 instance;

/*

 * 3 向外公布一个 公共的 静态的方法 ,返回内部保存的这个对象

 *   懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,

解决线程安全问题:

         可以加同步来解决。但是加了同步之后,每一次都要比较锁,效率就变慢了,

         所以可以加双重判断来提高程序效率。

 */

public static SingletonTest2 getInstance() {

if (instance == null) {

synchronized (SingletonTest2.class) {

if (instance == null) {

instance = new SingletonTest2();

}

}

}

return instance;

}

}

 

双重判断,对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (instance == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (instance == null),直接return实例化对象。

优点:线程安全;延迟加载;效率较高。

饿汉式和懒汉式的区别:

1饿汉式是类一加载进内存就创建好了对象;

2懒汉式则是类加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,对象才开始创建。

3懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,解决线程安全问题可以加同步来解决。但是加了同步之后,每一次都要比较锁,效率就变慢了,所以可以加双重判断来提高程序效率。

第四种实现方式:枚举的方式

示例代码:

package cn.itsource.sington;

public enum SingletonTest4 {

    INSTANCE;

}

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中,很少见人这么写过。

优点写法简单这是它最大的优点,其次可以自己处理序列化,是线程安全的

缺点当想实例化一个单例类的时候,必须要记住使用SingletonTest4.INSTANCE获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。

   以上是对单例模式常见的几种实现方式,在教学和学习过程中的一点简单的总结,希望对大家学习单例模式有一点点帮助。

猜你喜欢

转载自www.cnblogs.com/2018-fyj/p/8926084.html