PS:首先咱们要先知道什么是单例,为何要用单例,用的好处是什么等问题来看。html
一、单例类只能有一个实例。
二、单例类必须本身建立本身的惟一实例。
三、单例类必须给全部其余对象提供这一实例。java
单例模式确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具备资源管理器的功能。每台计算机能够有若干个打印机,但只能有一个Printer Spooler,以免两个打印做业同时输出到打印机中。每台计算机能够有若干通讯端口,系统应当集中管理这些通讯端口,以免一个通讯端口同时被两个请求同时调用。总之,选择单例模式就是为了不不一致状态,避免政出多头。
设计模式
先把单例类写出来缓存
public class SingletonTest { //懒汉式单例类.在第一次调用的时候实例化本身 private SingletonTest() {} private static SingletonTest single=null; //静态工厂方法 public static SingletonTest getInstance() { if (single == null) { single = new SingletonTest(); System.out.println("建立一次"); } return single; } public void show(){ System.out.println("我是show"); } }
这里直接上代码,代码中有详解安全
public class SingletonTest2 { public static void main(String[] args) { // TODO Auto-generated method stub //故意写获取两次,建立两个对象 SingletonTest singleton=SingletonTest.getInstance(); SingletonTest singleton2=SingletonTest.getInstance(); //Singleton对象只建立一次,可是写两次仍是能够的,并且方法都是能够调用的,可是看下面 singleton.show(); singleton2.show(); //两个对象的表现形式同样 if(singleton == singleton2){ System.out.println("该对象的字符串表示形式:"); System.out.println("singleton :"+singleton.toString()); System.out.println("singleton2:"+singleton2.toString()); } }
由上面的图能够看出就算多建立几个对象,在底部也是只有一个singleton对象实例,并且建立出来的对象的字符串表现形式也是同样的,有的人确定有疑问,那日常两个对象是什么样子的呢,我下面给你解释说明,在这以前我写说一下这个懒汉式须要注意的地方,它是线程不安全的,并发环境下极可能出现多个Singleton实例,有不少方法能够解决,好比说同步锁,静态内部类等,这里主要说静态内部类,这个比较好点,并发
public class Singleton3 { private static class SingletonHolder { private static final Singleton3 INSTANCE = new Singleton3(); } private Singleton3 (){} public static final Singleton3 getInstance() { System.out.println("singleton建立"); return SingletonHolder.INSTANCE; } }
调用:post
Singleton3 singleton3=Singleton3.getInstance(); Singleton3 singleton4=Singleton3.getInstance(); if(singleton3 == singleton4){ System.out.println("该对象的字符串表示形式:"); System.out.println("singleton3:"+singleton3.toString()); System.out.println("singleton4:"+singleton4.toString()); }
结果图:url
这里我也是建立了两个对象来讲明,神奇的是打印了两次singleton建立,这难道是又建立成功了的对象吗?答案是:虽然打印了两次,对象名也有两个,可是该对象的字符串表示形式仍是同样的,并且你们都知道static的用法,就是在类被加载的同时该singleton对象就已经被建立,后期不会再被建立,就算后期本身又调用了getInstance()方法,但底层仍是公用的一个Singleton对象.spa
一样,我写了一个普通的类,来同时建立两个对象,而且打印他们的toString()方法,以下:线程
QuBie qb1=new QuBie(); QuBie qb2=new QuBie(); if(qb1 == qb2){ System.out.println("该对象的字符串表示形式:"); System.out.println("singleton3:"+qb1.toString()); System.out.println("singleton4:"+qb2.toString()); }else{ System.out.println("该对象的字符串表示形式:"); System.out.println("singleton3:"+qb1.toString()); System.out.println("singleton4:"+qb2.toString()); }
由此可看出来对象的字符串表示形式是不同的
public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { return single; } }
由于这自己就是static修饰的方法,因此是在类加载的时候被建立,后期不会再改变,因此线程是安全的。