单例模式是创建型设计模式,用这个模式一般是用来创建对象,并且是创建对象,在原来学习单例模式时有几种写法,对于线程不安全的懒汉式曾经说过他不是严格的单例模式,现在来看看为什么这样说。
下面是懒汉式(线程不安全)的代码:
public class Singleton {
private static Singleton singleton = null;
private Singleton () {}
public static Singleton getSingleton () {
if (singleton == null) {
System.out.println("=====执行=====");
singleton = new Singleton();
}
return singleton;
}
}
这段代码在单线程中是没有什么问题的,但因为没有锁机制,在多线程下就出现问题,当同一时候有两个或以上的线程进入getSingleton()这个方法时,因为刚开始时singleton是null,而几个线程都是第一时间到达了这个方法里,所以if条件都满足,就会出现新建出不是唯一的Singleton对象,下面是用多线程测试的代码,我们使用set集合来存储创建出来的对象,因为set集合不能放重复的元素,如果每次获得的对象都是唯一的,那么set的大小始终为1,反之,则大于1。
public class SingletonThread implements Runnable {
public Set<Singleton> sets = new HashSet<Singleton>();
@Override
public void run() {
Singleton singleton = Singleton.getSingleton();
sets.add(singleton);
System.out.println("set的大小是:"+sets.size());
}
}
public class TestSingleton {
public static void main (String[] args) {
SingletonThread s = new SingletonThread();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
}
}
结果截图:
可以看到set的大小为2,说明创建出了两个不同的Singleton对象,其实我在getSingleton()方法里加了“=====执行=====”这句话,在结果中这句话被打印了两次也可以知道有两个线程同时进入并满足singleton==null条件然后都创建出了一个新的Singleton对象。
如果要想线程安全可以参考我原先写的单例模式的其他几种写法。