在编程中,单例模式是我们常用的一种设计模式,功能是保证在整个系统只用一个该对象的对象,具体代码如下:
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
return singleton;
}
return singleton;
}
}
上面的代码我们知道并不是线程安全的,在多线程环境下,容易造成创建多个对象。 测试代码如下:
@Test
public void testSingleton() throws InterruptedException {
for (int i=0;i<10;i++){
new Thread(()->{
Singleton.getInstance();
}).start();
}
Thread.currentThread().join();
}
运行结果如下:
创建对象
创建对象
创建对象
创建对象
创建对象
创建对象
创建对象
对于上面的问题解决的方法有很多,比如使用加锁的方式,double检测的方式,为了验证最有方案我们把代码修改下:
public class Singleton {
private static Singleton singleton;
private Singleton() {
try {
Thread.sleep(10);//增加创建对象的耗时
} catch (Exception e) {
}
}
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
return singleton;
}
}
return singleton;
}
}
测试代码:
@Test
public void testSingleton() throws InterruptedException {
long start=System.currentTimeMillis();
List<Thread> threadList = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(() -> {
Singleton.getInstance();
});
threadList.add(thread);
thread.start();
}
for (Thread t : threadList) {
t.join();
}
long end=System.currentTimeMillis();
System.out.println("运行耗时:"+(end-start));
}
public static Singleton getInstance() {
synchronized (Singleton.class){
if (singleton == null) {
System.out.println("创建对象");
singleton = new Singleton();
}
}
return singleton;
}
经过多次测试时间维持在410ms左右,下面是一次测试结果
运行耗时:410
这个虽然成功的保证了只有一个对象,但同样也会把其他的线程阻塞在创建的锁的前面,造成了性能上面的开销,如果创建一个对象的时间比较长,这个性能的开销是相当可观的。
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
return singleton;
}
}
}
return singleton;
}
运行耗时:380
上面的代码虽然聪明的避开的过多线程等待的原因,但是彻底消除线程排队的现象,因为创建对象分需要耗时,这样就给其他线程提供了“可乘之机”
共享变量是线程间同步的“轻量级锁”,彻底消除线程排队的现象,此处用于单例模式的设计,能够实现最小性能的开销:
private volatile static Singleton singleton;
运行耗时:280