- 模式一:
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
这个模式线程安全,但是也有自己的缺点。当为如下情况时,初始化就会产生问题!
public class SingletonAa {因为初始化依赖于static变量,而这些初始化函数在变量被初始化之前被调用了...所以会跑出NullPointException。
private static SingletonAa singletonAa = new SingletonAa();
public static String name = "sam";
public static String password;
static {
password = "tiger";
}
private SingletonAa(){
if(name.equals("sam")) System.out.println("name is ok");
if(password.equals("tiger")) System.out.println(" password is ok");
}
public static SingletonAa getInstance() {
return singletonAa;
}
}
- 模式二:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singletion();
}
return instance;
}
}
模式一会在程序使用时就初始化instance,而模式二是在第一次调用getInstance时使用。如果初始化较为繁琐,那么显然模式二会更好一点。但是该模式还是有缺点,就是对多线程使用了同步锁。
以上的模式是线程安全的,又是延迟初始化,而且同步的范围缩到最小。其中创建temp的原因是为了避免Java的无序写入导致的初始化未完成就返回结果。具体参看:http://www.ibm.com/developerworks/cn/java/j-dcl.html
但事实上经过测试得到的是同一单例,测试代码如下:
- 模式三
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
Singleton temp = new Singletion(); //防止无序写入导致的多线程问题
instance = temp;
}
}
}
return instance;
}
}
以上的模式是线程安全的,又是延迟初始化,而且同步的范围缩到最小。其中创建temp的原因是为了避免Java的无序写入导致的初始化未完成就返回结果。具体参看:http://www.ibm.com/developerworks/cn/java/j-dcl.html
- 模式四:
public class Singleton {起初我看到这个代码的时候还认为它不是线程安全的,因为考虑到并发情况下,instance可能被初始化多次,所以得到的并不是单例而是多个。
static class SingletonsHolder {
static Singletons instance = new Singletons();
}
public static Singletons getInstances() {
return SingletonsHolder.instance;
}
}
但事实上经过测试得到的是同一单例,测试代码如下:
public class Singletons {上述代码完成的过程是:
public static boolean b = true;
private Singletons() {
System.out.println("In " + b);
if (b) {
System.out.println("Sleeping " + b);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Singletons " + b);
}
static class SingletonsHolder {
static Singletons instance = new Singletons();
}
public static Singletons getInstances() {
System.out.println("getInstances");
return SingletonsHolder.instance;
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Start");
new Thread() {
public void run() {
System.out.println(Singletons.getInstances());
}
}.start();
Thread.sleep(1000);
Singletons.b = false;
new Thread() {
public void run() {
System.out.println("Two Start");
System.out.println(Singletons.getInstances());
System.out.println("Two End");
}
}.start();
System.out.println("End ");
}
}
- 开始;
- 线程1获取单例;
- b为true,故线程1 sleep 5秒;
- 主线程sleep 1秒;
- b被设置为false;
- 线程2获取单例;
Start
getInstance
In true
Sleeping true
等待了1秒
End
Two Start
getInstance
等待了4秒
Singletons false可见最终得到的单例是同一个。分析我们知道测试的执行过程为:
org.my.test.singleons.Singletons@1a758cb
org.my.test.singleons.Singletons@1a758cb
Two End
- 开始;
- 线程1获取单例,进入Singletons初始化函数
- b为true,故线程1 sleep 5秒;
- 主线程sleep 1秒;
- b被设置为false;
- 线程2获取单例,进入Singletons的getInstances()方法,发现SingletonsHolder还未被初始化完成,并且发现它正在被初始化,故等待;
- 线程1成功初始化instance完成,并输出结果;
- 线程2等待结束获取了初始化完成的instance,并输出结果;
没有评论:
发表评论