Java中单例设计模式,饿汉式和懒汉式

23 篇文章 1 订阅
14 篇文章 0 订阅
单例模式是一种常用的软件设计模式,确保一个类只有一个实例并提供全局访问点。本文详细介绍了单例模式的实现方式,包括饿汉式和懒汉式,以及它们的区别和线程安全问题。饿汉式在类加载时即创建实例,而懒汉式在首次调用时创建。为了线程安全,懒汉式可采用同步锁、双重检查锁定和静态内部类等策略。单例模式常应用于计数器、日志应用、数据库连接池等场景。
摘要由CSDN通过智能技术生成

单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

如果我们要让类在一个虚拟机中只能产生一个对象:

  1.     将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。
  2.     提供一个public方法作为该类的访问点,用于创建该对象,必须是static修饰的,因为在类的外部开始还无法得到类的对象,只能通过类调用该方法。
  3.     缓存已创建的对象,否则该类无法知道是否已经创建了对象。静态方法只能访问类中的静态成员变量,所以该类对象的变量也必须定义成静态的。

注意

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

实例的步骤

  • 私有的构造器
  • 私有的,静态的,该类的引用
  • 公共的静态的访问方式

单例模式的优点:

        由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

单例模式-应用场景

  1.     网站的计数器:一般也是单例模式实现,否则难以同步。
  2.     应用程序的日志应用:一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  3.     数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
  4.     项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
  5.     Application 也是单例的典型应用。
  6.     Windows的Task Manager (任务管理器) 就是很典型的单例模式
  7.     Windows的Recycle Bin (回收站) 也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

单例设计模式一般有两种方式:饿汉式和懒汉式。

其最大的区别是看其什么时候创建对象,如果一开始就创建实例对象,则是饿汉式。

  • 饿汉式和懒汉式的区别:
    • 饿汉式:一开始就创建实例对象
      • 优点:线程是安全的。
      • 缺点:对象加载时间过长。
    • 懒汉式:需要的时候才创建对象的设计模式
      • 缺点:应用同步,存在线程安全问题,可以使用多线程锁来解决。
      • 优点:延迟对象的创建(延迟加载)
  • 饿汉式实例:在类第一次加载完成之后,就创建实例

// 饿汉式
class Maike{
    //1.私有构造器
    private Maike(){}
    //2. 在类内部创建对象
    private static Maike instance = new Maike();

    //3. 提供外部访问点
    public static Maike getInstance (){
        return instance;
    }
}
//测试
public class SingleTest{
	public static void main(String[ args]){
		Maike maike=Maike.test();
	}
}
///******************//****************
//饿汉式 枚举方式
/**
 * Title:Singleton<br>
 * Description:单例模式——枚举方式
 * 
 * @author QiuChangjin
 * @date 2018年4月17日
 */
public class Singleton {
    public static void main(String[] args) {
        Single single = Single.SINGLE;
        single.print();
    }

    enum Single {
        SINGLE;

        private Single() {
        }

        public void print() {
            System.out.println("hello world");
        }
    }
}
  • 懒汉式实例: 第一次调用时候,才创建实例

//懒汉式
class Maike{
    private Maike()
    {

    }
    private static Maike instance=null;

    public static Maike getInstance()
    {
        if (instance==null)
        {
            instance = new Maike();
        }
        return instance;
    }

}
//测试
public class SingleTest{
	public static void main(String[ args]){
		Maike maike=Maike.test();
	}
}

        懒汉式:保证线程安全通过 同步锁 synchronized

        1.在getInstance方法上加同步(性能较差)

           在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的

//同步方法,效率较低,范围大
public static synchronized Single test(){
	if(single==null){
		single=new Single();
	}
	return single;
}

//同步判断
public static synchronized Single test(){
	synchronized (Single.class) {
		if(single==null){
			single = new Single();
		}
	}
	return single;
}

        2.双重检查锁定(DCL 双检查锁机制) 推荐

           在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗

//双重检查  double check:锁的范围小,效率高
public static SingleTon01 newInstance(){
	if(single==null){
		synchronized (Single.class) {
		    if(single==null){
				single = new Single();
			}
		}
    }
	return singleTon;
}

        3.静态内部类  推荐

public class Singleton {
    /**
     * 私有构造方法,禁止在其他类中创建实例
     */
    private Singleton(){}
    /**
     * 一个私有的静态内部类,用于初始化一个静态final实例
     */
    private static class SingletonHolder{
        private final static Singleton instance=new Singleton();
    }
    /**
     * 获取实例
     */
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

对于单例模式的几种实现方式,知道饿汉式和懒汉式的区别,线程安全,资源加载的时机,还有懒汉式为了实现线程安全的3种方式的细微差别。

一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举方式来实现单例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值