什么是单例模式?
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式的特点:
1、单例类有且只能有一个实例。
2、单例类需要自己创建一个自己的实例。
3、单例类需要为其他类提供这个实例。
哪些地方经常用到单例?
在计算机系统中,配置文件,线程池,缓存,日志对象,打印机等经常用到单例模式
所谓“一山不容二虎”,如果出现二虎很容易会出问题,比如配置文件,它终究只是一个文件,如果同时有好几个实例访问它并执行修改操作,那么这时候就会引发出一系列的问题
单例相对于多实例对象也更节约系统资源
单例模式常用的有几种模式?
一般来讲单例模式有三种,分别是:懒汉式,饿汉式,登记式。
下面直接上代码说明吧
①一个类之所以能够创建出实例是因为有构造方法的存在,只要我们把构造方法的访问修饰符改成私有(private),外界就不能通过new来创建该类的实例。
②在单例类中自身new出一个对象,因为要被外界访问,我们可以把它静态化(static),以便外界访问(类型.对象)。
③有时候我们需要控制这个对象,也处于安全起见,我们可以把继续私有化(private),然后提供一个getter方法以便外界访问。
SimpletonDemo1.java(单例类)
1 package com.lcw.simpleton; 2 3 public class SimpletonDemo1 { 4 //将构造方法私有化,阻止外界直接创建对象 5 private SimpletonDemo1() { 6 } 7 //提供static以便外界访问 8 private static SimpletonDemo1 instance = new SimpletonDemo1(); 9 10 //提供getter方法以便外界访问私有化对象,static SimpleDemo1返回类型 11 public static SimpletonDemo1 getInstance() { 12 return instance; 13 } 14 }
SimpletonTest.java(测试类)
1 package com.lcw.simpleton; 2 3 public class SimpletonTest { 4 public static void main(String[] args) { 5 SimpletonDemo1 s1=SimpletonDemo1.getInstance(); 6 SimpletonDemo1 s2=SimpletonDemo1.getInstance(); 7 8 if(s1==s2){//检测对象的内存地址是否一致 9 System.out.println("s1和s2是同个对象"); 10 }else{ 11 System.out.println("s1和s2不是同个对象"); 12 } 13 14 } 15 }
效果如下:
上面所说的就是单例模式里饿汉模式,为什么叫饿汉模式呢?
由于这个实例是被static所修饰,被static修饰的成员属于类所有,当类加载的时候,这个成员就被加载了,也就是说不管外界是否调用这个类,它都已经被加载了。
看起来好像是饿汉,不管三七二十一,先吃了你再说。
下面再来看下单例模式中的懒汉模式
就字面上的意思,其实已经很明白了“懒汉模式”,顾名思义不同于饿汉模式,既然饿汉模式是不管三七二十一先吃了再说,那么懒汉模式当然就没那么勤快了,应该是被我们调用后的时候才去实例化对象。
它们的写法很类似,只不过是在用private static声明对象的时候不直接new对象,而是在gette方法里再去实例化对象
然后判断下这个对象是否为null,如果为null则实例化一个对象,如果不会空则直接返回对象。
下面看下具体代码
SimpletonDemo2.java(单例类)
1 package com.lcw.simpleton; 2 3 public class SimpletonDemo2 { 4 //将构造方法私有化,阻止外界直接创建对象 5 private SimpletonDemo2() { 6 } 7 //提供static以便外界访问 8 private static SimpletonDemo2 instance = new SimpletonDemo2(); 9 10 //提供getter方法以便外界访问私有化对象,static SimpleDemo1返回类型 11 public static SimpletonDemo2 getInstance() { 12 return instance; 13 } 14 }
SimpletonTest.java(测试类)
1 package com.lcw.simpleton; 2 3 public class SimpletonTest { 4 public static void main(String[] args) { 5 SimpletonDemo1 s1=SimpletonDemo1.getInstance(); 6 SimpletonDemo1 s2=SimpletonDemo1.getInstance(); 7 8 if(s1==s2){//检测对象的内存地址是否一致 9 System.out.println("s1和s2是同个对象"); 10 }else{ 11 System.out.println("s1和s2不是同个对象"); 12 } 13 14 15 SimpletonDemo2 s3=SimpletonDemo2.getInstance(); 16 SimpletonDemo2 s4=SimpletonDemo2.getInstance(); 17 18 if(s3==s4){//检测对象的内存地址是否一致 19 System.out.println("s3和s4是同个对象"); 20 }else{ 21 System.out.println("s3和s4不是同个对象"); 22 } 23 24 } 25 }
效果如下:
总结下两种模式的区别:
1、饿汉模式,在加载类的时候比较慢,由于它还要去实例化一个对象,但在运行调用中的速度会比较快。
2、懒汉模式,在加载类的时候比较快,由于在加载类的时候不需要去实例化对象,但在运行调用时的速度比较慢,由于还要去做判断。
还有一点很重要的是,饿汉模式是属于线程安全,而懒汉模式属于线程不安全。