final Set
final TestSingleton lock = new TestSingleton();
lock.setLock(true);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
public void run() {
while (true) {
if (!lock.isLock()) {
Singleton singleton = Singleton.getInstance();
instanceSet.add(singleton.toString());
break;
}
}
}
});
}
Thread.sleep(5000);
lock.setLock(false);
Thread.sleep(5000);
System.out.println("------并发情况下我们取到的实例------");
for (String instance : instanceSet) {
System.out.println(instance);
}
executorService.shutdown();
}
}
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestSingleton {
boolean lock ;
public boolean isLock() {
return lock;
}
public void setLock(boolean lock) {
this.lock = lock;
}
public static void main(String[] args) throws InterruptedException {
final Set
final TestSingleton lock = new TestSingleton();
lock.setLock(true);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
public void run() {
while (true) {
if (!lock.isLock()) {
Singleton singleton = Singleton.getInstance();
instanceSet.add(singleton.toString());
break;
}
}
}
});
}
Thread.sleep(5000);
lock.setLock(false);
Thread.sleep(5000);
System.out.println("------并发情况下我们取到的实例------");
for (String instance : instanceSet) {
System.out.println(instance);
}
executorService.shutdown();
}
}
我在程序中同时开启了100个线程,去访问getInstance方法,并且把获得实例的toString方法获得的实例字符串装入一个同步的set集合,set集合会自动去重,所以看结果如果输出了两个或者两个以上的实例字符串,就说明我们在并发访问的过程中产生了多个实例。
程序当中让main线程睡眠了两次,第一次是为了给足够的时间让100个线程全部开启,第二个是将锁打开以后,保证所有的线程都已经调用了getInstance方法。
好了,这下我们用事实说明了,上述的单例写法,我们是可以创造出多个实例的,至于为什么在这里要稍微解释一下,虽说我一直都喜欢用事实说话,包括看书的时候,我也不喜欢作者跟我解释为什么,而是希望给我一个例子,让我自己去印证。
造成这种情况的原因是因为,当并发访问的时候,第一个调用getInstance方法的线程,在判断完singleton是null的时候,就进入了if块准备创造实例,但是同时另外一个线程在第一个调用的线程还未创造出来之前,就又进行了singleton是否为null的判断,这时singleton依然为null,所以第二个线程也会进入if块去创造实例,这时问题就出来了,有两个线程都进入了if块去创造实例,结果就造成单例模式并非单例。
为了避免这种情况,我们就要考虑并发的情况了,我们最容易想到的方式应该是下面这样的方式。
[java]
public class BadSynchronizedSingleton {
//一个静态的实例
private static BadSynchronizedSingleton synchronizedSingleton;
//私有化构造函数
private BadSynchronizedSingleton(){}
//给出一个公共的静态方法返回一个单一实例
public synchronized static BadSynchronizedSingleton getInstance(){
if (synchronizedSingleton == null) {
synchronizedSingleton = new BadSynchronizedSingleton();
}
return synchro