设计模式 – 单例模式(Singleton)

ü  核心:保证一个类仅有一个实例,并提供一个访问它的全局访问点;

ü  用途:想保证某个特定类的对象实例绝对只有1个的情况;

ü  结构图:

ü  方法:可以把类的属性定义为static字段,再以Singleton类的对象实例进行初始化,而这个初始化的操作仅仅在加载Singleton类时进行一次,Singleton类的构造函数是private(所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效,因此写成private,外部程序就不能用new来实例化该类了),主要是为了禁止从非Singleton类调用构造函数new出新的实例,而向要取得Singleton类的惟一对象实例的方法就是getInstance

ü  单例模式和实用类的区别:实用类通常也会采用私有化的构造方法来避免其有实例,但是实用类不保存状态,仅提供一些静态方法或者静态属性让你使用,而单例类是有状态的,实用类不能用于继承多态,而单例虽然实例唯一,却是可以有子类来继承的,实用类只不过是一些方法属性的集合,而单例却是有这唯一的对象实例。

ü  还需要注意,在多线程的程序中,多个线程同时访问Singleton类,调用getInstance方法,会有可能造成创建多个实例。这个时候可以利用JAVA里的线程同步机制,为getInstance方法添加synchronized关键字(但不能对单例的实例化对象instance添加锁,因为该对象可能尚未实例化),而避免每次加锁影响性能,可以使用双重锁定”(Double-Check Locking)

    说明:仔细观察,我们不难发现,上述程序中有两个地方需要判断instance是否为空,这主要是因为:当instancenull并且同时有两个线程调用GetInstance()方法时,它们都将可以通过第一重instance == null的判断,然后由于lock机制,这两个线程则只有一个可以进入,另一个在外排队等候,必须要其中的一个进入并出来后,另一个才能进入,而不要误以为只能执行其中一个,因此没有第二重的Instance是否为空的判断,则两个线程都会同时创建出实例,没有达到单例的目的。

实例一:

Ø  单例类 -- 文件Singleton.java

package com.yilong.designpattern.singleton;

public class Singleton {

    private static Singleton singleton = new Singleton();

    private int ticketId = 1000;

    private Singleton() {

       System.out.println("已产生对象实例");

    }

    public static Singleton getInstance() {

       return singleton;

    }

    public int getNextTicketId() {

       return ticketId ++;

    }

}

Ø  测试类 文件Main.java

package com.yilong.designpattern.singleton;

public class Main {

    public static void main(String[] args) {

       System.out.println("Start");

       Singleton singleton1 = Singleton.getInstance();

       Singleton singleton2 = Singleton.getInstance();

       System.out.println(singleton1 == singleton2);

       System.out.println(singleton1);

       System.out.println(singleton2);

       System.out.println(singleton1.getNextTicketId());

       System.out.println(singleton2.getNextTicketId());

       System.out.println("End");

    }

}

打印结果:

Start

已产生对象实例

true

com.yilong.designpattern.singleton.Singleton@c17164

com.yilong.designpattern.singleton.Singleton@c17164

1000

1001

End

实例二:通过判断对象实例是否为空的方法实例化,但是这种方法在多线程的结构下可能达不到预期的效果,所以最好在方法前添加关键字synchronized

Ø  单例类 文件Singleton1.java

package com.yilong.designpattern.test;

public class Singleton1 {

    private static Singleton1 testSingleton = null;

    private Singleton1() {

       System.out.println("初始化!");

    }

    public static synchronized Singleton1 getInstance() {

       if(testSingleton == null) {//尽管加入了锁,但这个判断还是必须的

           testSingleton = new Singleton1();

       }

       return testSingleton;

    }

}

实例三:实例数目有限个的情况。

Ø  文件Singleton2.java

package com.yilong.designpattern.test;

public class Singleton2 {

    public static final int SIZE = 3;

    private int id;

    private static Singleton2[] singletons =

           {new Singleton2(0), new Singleton2(1), new Singleton2(2)};

    private Singleton2(int id) {

       System.out.println("初始化!");

       this.id = id;

    }

    public static synchronized Singleton2 getInstance(int id) {

       if(id>=0 && id<=3) {

           return singletons[id];

       } else {

           return null;

       }

    }

}

Ø  测试类 文件Test2.java

package com.yilong.designpattern.test;

public class Test1 {

    public static void main(String[] args) {

       System.out.println("Start");

       Singleton2 singleton1 = Singleton2.getInstance(0);

       Singleton2 singleton2 = Singleton2.getInstance(1);

       Singleton2 singleton3 = Singleton2.getInstance(2);

       Singleton2 singleton4 = Singleton2.getInstance(0);

       System.out.println(singleton1);

       System.out.println(singleton2);

       System.out.println(singleton3);

       System.out.println(singleton1 == singleton4);

       System.out.println("End");

    }

}

打印结果:

Start

初始化!

初始化!

初始化!

com.yilong.designpattern.test.Singleton2@c17164

com.yilong.designpattern.test.Singleton2@1fb8ee3

com.yilong.designpattern.test.Singleton2@61de33

true

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章