单例模式算是设计模式中最简单的模式,在我们的项目中经常会用到,网上资料也很多,我这主要讲单例模式的使用场景及单例模式的特性。
先看个简单单例模式例子:
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
下来进行测试:
public class TestSingleton {
@Test
public void test() {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1);
System.out.println(singleton2);
}
}
com.design.pattern.Singleton@30946e09
com.design.pattern.Singleton@30946e09
可见对象的结果一样,说明无论你调用多少次,Singleton类只会生成一个对象,这就是单例模式。
下来看下满足单例模式的条件:
1.私有构造方法,禁止通过new创建对象。否则单例模式就是去意义了。
2.自己的静态实例,指向自己的static变量。
3.返回自己静态实例的静态公有方法
4.判断自己的静态变量是否为null,为null创建个对象否则直接返回。
单例模式优点:
无论怎么调用都只有一个对象,节省内存空间,
避免频繁创建销毁对象,提高性能
避免对共享资源的多重占用
可以全局使用
下来我讲单例模式在多线程下的
@Test
public void test_multhread() {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
Singleton singleton = Singleton.getInstance();
System.out.println(singleton);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
输出结果:
com.design.pattern.Singleton@5196823d
com.design.pattern.Singleton@70a924d6
com.design.pattern.Singleton@5196823d
com.design.pattern.Singleton@5196823d
......
看到没,出现了多个实例,
所以在并发情况下,这种单例模式是不稳定的。
那我们如何保证并发情况下也只有这一个实例呢,那就是加锁。
public synchronized static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
在这里我们把整个方法同步,一次只能一个对象调用,避免多个对象调用;但是这会造成后面的对象挂起,必须等前面的处理完才能进行,效率非常低。如果对象已经有实例,就不需要进到if判断,但是还是得等待,这势必浪费资源。
我们再次优化,缩小同步的范围:
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
这样就过滤掉已经有实例情况下,不需要再等待,效率提升。但是这块有个潜在的问题,如果A和B同时进到if判断里面,A先操作,new一个实例,B进来的时候还是会再new一个实例,这就违背单例模式的初衷,那在B进入的时候判断下是否A已经实例化过了,如果实例化了就直接返回实例。
再次优化如下:
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}