基本概念
Singleton 是一种创建性模型,它用来确保只产生一个实例,并提供一个访问它的全局访问点.对一些类来说,保证只有一个实例是很重要的,比如有的时候,数据库连接或 Socket 连接要受到一定的限制,必须保持同一时间只能有一个连接的存在.再举个例子,集合中的 set 中不能包含重复的元素,添加到set里的对象必须是唯一的,如果重复的值添加到 set,它只接受一个实例.JDK中正式运用了Singleton模式来实现 set 的这一特性,大家可以查看java.util.Collections里的内部静态类SingletonSet的原代码.其实Singleton是最简单但也是应用最广泛的模式之一,在 JDK 中随处可见.
简单分析
为了实现 Singleton 模式,我们需要的是一个静态的变量,能够在不创建对象的情况下记忆是否已经产生过实例了.静态变量或静态方法都可以在不产生具体实例的情况下直接调用,这样的变量或方法不会因为类的实例化而有所改变
Singleton 模式用来保证在运行的应用程序中,一个Class只是实例化一次,也就是只有一个相应的对象存在。在 web 程序中我们会用一个核心的分配功能的Servlet程序,在这里我们就可以运用这种设计模式了。
一般Singleton模式通常有几种形式:
第一种形式:
定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
package testSingleton;
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
Singleton singleton1 = Singleton.getInstance();
if (singleton == singleton1) {
System.out.println("same");
}else {
System.out.println();
}
}
}
第二种形式:线程安全、延迟创建的单例
package testSingleton;
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次使用时生成实例,提高了效率!
if (instance == null)
instance = new Singleton();
return instance;
}
}
第三种形式:double checked locking singleton ( 仅适用于java 5.0 以上版本。只同步局部代码,多线程高并发访问情况)
package testSingleton;
public class DoubleCheckSingleton {
// java5.0 修改了内存模型, 可以保证使用volatile 声明的变量对于double checked locking是正确的
private volatile static DoubleCheckSingleton instance = null;
public static DoubleCheckSingleton getInstance() {
if (instance == null) {// check if it is created.
synchronized (DoubleCheckSingleton.class) {//synchronize create block
if (instance == null) {// double check if it is created.
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
第四种形式:Initialization on demand holder (线程安全、延迟创建的单例)
package testSingleton;
public class LazyLoadedSingleton {
// 当JVM加载LazyLoadedSingleton类时,由于该类没有static属性,所以加载完成后即可返回。
// 只有第一次调用getInstance()方法时,JVM才会加载LazyHolder类,由于它包含一个static属性singletonInstance,
// 所以会首先初始化这个变量,该过程不会出现并发问题,这样就实现了一个既线程安全又支持延迟加载的单例模式
private LazyLoadedSingleton() {
}
private static class LazyHolder {
private static final LazyLoadedSingleton singletonInstance = new LazyLoadedSingleton();
}
public static LazyLoadedSingleton getInstance() {
return LazyHolder.singletonInstance;
}
}
测试
package test4JavaStudy.thread;
//线程安全的Singleton模式
class Singleton {
private static Singleton sample;
public synchronized static Singleton getInstance() {
if (sample == null) {
// 为了放大Singleton模式的线程不安全性
Thread.yield();
sample = new Singleton();
}
return sample;
}
}
public class TestThread extends Thread {
public void run() {
Singleton singleton = Singleton.getInstance();
System.out.println(singleton.hashCode());
}
public static void main(String[] args) {
Thread threads[] = new Thread[5];
for (int i = 0; i < threads.length; i++)
threads[i] = new TestThread();
for (int i = 0; i < threads.length; i++)
threads[i].start();
}
}