ü 核心:保证一个类仅有一个实例,并提供一个访问它的全局访问点;
ü 用途:想保证某个特定类的对象实例绝对只有1个的情况;
ü 结构图:
ü 方法:可以把类的属性定义为static字段,再以Singleton类的对象实例进行初始化,而这个初始化的操作仅仅在加载Singleton类时进行一次,Singleton类的构造函数是private的(所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效,因此写成private,外部程序就不能用new来实例化该类了),主要是为了禁止从非Singleton类调用构造函数new出新的实例,而向要取得Singleton类的惟一对象实例的方法就是getInstance。
ü 单例模式和实用类的区别:实用类通常也会采用私有化的构造方法来避免其有实例,但是实用类不保存状态,仅提供一些静态方法或者静态属性让你使用,而单例类是有状态的,实用类不能用于继承多态,而单例虽然实例唯一,却是可以有子类来继承的,实用类只不过是一些方法属性的集合,而单例却是有这唯一的对象实例。
ü 还需要注意,在多线程的程序中,多个线程同时访问Singleton类,调用getInstance方法,会有可能造成创建多个实例。这个时候可以利用JAVA里的线程同步机制,为getInstance方法添加synchronized关键字(但不能对单例的实例化对象instance添加锁,因为该对象可能尚未实例化),而避免每次加锁影响性能,可以使用”双重锁定”(Double-Check Locking):
说明:仔细观察,我们不难发现,上述程序中有两个地方需要判断instance是否为空,这主要是因为:当instance为null并且同时有两个线程调用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