6、单子模式(单例模式)
一、功能:保证在整个应用中只有一个实例存在。(例如只创建一个窗口,JDBC连接数据库程序只连接一个等)。
二、概念:对某个类只能存在一个对象实例,并且该类提供了一个取得其对象实例的方法。
三、单子模式第一种写法:
步骤:1、首先私有化构造器,这样在外部就不能随意new对象了
2、在类的内部定义并产生那个唯一的对象,并限制其访问权限为private
3、提供给外部一个public类型的静态方法,可以获得该唯一对象。
/** * Created by Administrator on 2018/3/1 0001. * 最典型的单例模式、单子模式 */ public class A { private A(){}//第一步:私有化构造器,这样主类就不能随意的实例化多个对象了 private static A a=null;//第二步:初步定义对象,方便后面方法中调用判断该变量 public static A Getinstance(){//这里必须是静态方法,因为当没有对象时,无法在主类中调用该方法。 if(a==null){ //第三步:如果没有a对象,就实例化,有的话就返回当前的对象 a=new A(); } return a; } }
/** * Created by Administrator on 2018/3/1 0001. */ public class TestA { public static void main(String[] args) { A a1=A.Getinstance(); A a2=A.Getinstance(); System.out.println(a1==a2); } }
缺点:在多线程中不能正常工作
四、单子模式第二种写法
这种写法能够在多线程中很好的工作:不需要同步。
/** * Created by Administrator on 2018/3/1 0001. * 多线程时保证单个线程调用的单例模式、单子模式,效率低下 */ public class B { private B(){} private static B b=null; public synchronized static B Getinstance(){ if(b==null){ b=new B(); } return b; } }
/** * Created by Administrator on 2018/3/1 0001. */ public class TestB { public static void main(String[] args) { B b1=B.Getinstance(); B b2=B.Getinstance(); System.out.println(b1==b2); } }
缺点:效率低下
五、单子模式的第三种写法
使用classloader的反射机制来保证初始化instance时只有一个线程。
使用内部类
/** * Created by Administrator on 2018/3/1 0001. * 使用classloader来保证初始化instance时只有一个线程,先加载C类,当需要时再调用Getinstance方法,加载C1类,初始化 */ public class C { public static class C1{ private static final C1 c=new C1();//final的定义就是不可再被更改 } public static C1 Getinstance(){ return C1.c; } }
/** * Created by Administrator on 2018/3/1 0001. */ public class TestC { public static void main(String[] args) { C.C1 c1=C.Getinstance(); C.C1 c2=C.Getinstance(); System.out.println(c1); System.out.println(c2); } }
六、单子模式第四种写法
用volatile来锁定变量,用synchronize锁定方法的双重锁定单子模式
public class D { private D(){} private volatile static D d=null;//在jvm的底层对变量进行单线程操作 public synchronized static D Getinstance(){//synchronized锁定方法 if(d==null){ d=new D(); } return d; } }
public class TestD { public static void main(String[] args) { D d1=D.Getinstance(); D d2=D.Getinstance(); System.out.println(d1==d2); } }