java设计模式之-----单例设计模式

来源:互联网 发布:python gnu readline 编辑:程序博客网 时间:2024/06/16 07:59

1.定义

单例设计模式:顾名思义,一个类只能产生一个实例,也就是说一个类只能有一个对象。就像古代的皇帝一样,只能有一个,多一个也不可以,这就是单例设计模式。

2.步骤及要点(注意)

  • 私有化构造函数
  • 提供一个本类的实例
  • 提供一个对外的供外界访问的方法

实现过程

  1. 最简单的单例模式
        (1)恶汉式
     public class SingelInstance {    // 私有化构造函数    private SingelInstance() {    }    // 产生一个实例对象    private static SingelInstance singleInstance = new SingelInstance();    // 提供一个供外界访问的方法    public static SingelInstance getInstance() {        return singleInstance;    }}
(2)懒汉式
 public class SingelInstance1 {    private SingelInstance1() {    }    private static SingelInstance1 singelInstance1;    public static SingelInstance1 getSingelInstance1() {    //假如同步关键字        synchronized (SingelInstance1.class) {            if(singelInstance1 == null){                singelInstance1 = new SingelInstance1();            }        }        return singelInstance1;    }}

比较: 恶汉式与懒汉式的区别仅在于先 new 与后 new 的问题,从名字就可以看出.懒汉式可以在需要的时候再new 对象,而恶汉式则是不管什么先 new 了一个对象.懒汉式的get 方法中要注意多线程的同步问题.为什么?java中new 一个对象不是简单的一个new 就能 new 出来的,只是我们自己这么觉得,其实,在编译后的执行的步奏中要经过几部才能产生出一个对象,假如不加入同步,就可能多个线程进入get 方法中产生多个对象.
注意: synchronized 关键字中不能用this关键字,为什么? 因为这个方法是静态的,静态优先于非静态,随着类的加载而加载,当对象还没产生时,静态方法就已经载入了,所以不能用this关键字,但是可以用类的class对象,原因前面已经说了.

(3)懒汉式(双重非空判断)

 public class SingelInstance2 {    private SingelInstance2() {    }    private static SingelInstance2 singelInstance2;    public static SingelInstance2 getSingelInstance2() {    //双重非空判断        if (singelInstance2 == null) {            synchronized (SingelInstance1.class) {                if (singelInstance2 == null) {                    singelInstance2 = new SingelInstance2();                }            }        }        return singelInstance2;    }}

为什么这样做: 在未加入双重非空判断的实例中,多个线程每次调用的get 方法中都要对对象上锁,事实上,只有在第一次创建的时候才需要对对象上锁,之后就不要了,因为对象已经new 出来了,之后只要直接返回就可以了,所以多加入一层非空判断有利于性能的提升.
分析: 假如现在有两个线程,A, B.
A,b线程同时进入了第一个if 判断,
A首先进入同步代码块,singelInstance2 为null,紧接着new 出了一个对象.由于jvm的优化机制,jvm给SingelInstance2 分配了存储空间,并复制给了成员变量singelInstance2 .(此时还没有实例化singelInstance2 ),然后A 离开了同步代码块.
此时B进入了同步代码块,由于此时singelInstance2 不为空,紧接着B出去了,并return 了singelInstance2.
此时B打算使用singelInstance2 ,但是singelInstance2 还没有实例化成对象,于是错误发生了.

(4) 静态内部类单例模式

     public class SingelInstance3 {    private SingelInstance3() {    }    private static class SingelInstanceFactory {        private static SingelInstance3 singelInstance3 = new SingelInstance3();    }    public SingelInstance3 getSingelInstance3() {        return SingelInstanceFactory.singelInstance3;    }}

为什么这样可以:
jvm内部机制能够保证一个类被加载的时候,这个类加载的过程式互斥的,这样当我们第一次调用getSingelInstance3
的时候,jvm能够保证singelInstance3
只被创建一次,并且会保证把赋值给singelInstance3内存空间初始化完毕,这样我们就解决了刚才的问题,同时该方法也只会在第一次调用的时候使用互斥机制,同时也解决了性能上的问题.

0 0