单例设计模式
Singleton单例设计模式:主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
这样的模式有几个好处:
- 1)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
- 2)省去了 new 操作符,降低了系统内存的使用频率,减轻 GC 压力。
- 3)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程
一般Singleton模式通常有几种形式:
1)第一种形式:饿汉式
- 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例化,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
2)第二种形式:饿汉式
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance;
}
}
单例设计模式的线程安全性
1.饿汉式
- 类加载时就会创建对象 --> 故,不会出现线程安全问题;
- 缺点:对比懒汉式需要时才会创建对象
class Hungry{
private static Hungry hungry = new Hungry();
private Hungry(){}
public static Hungry getInstance(){
return hungry;
}
}
2.懒汉式
- 优点:需要时才会创建对象;
- 会出现线程安全问题:因为有是否需要创建对象的判断,所以多线程执行创建对象的方法时,可能会出现创建出多个对象的情况
//懒汉式——单例模式
class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){ //多线程时,是否为null可能出现不同步的问题
instance=new Singleton();
}
return instance;
}
}
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
while(true){
Lazy z = Lazy.getLazy();
try { //增加多线程安全性出现的概率
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前线程名称与实例化对象的地址,用于判断单例模式是否失败
System.out.println(Thread.currentThread().getName() + ":" +z);
}
}
};
//创建三个线程,分别创建单例模式的对象
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
改进:
- 1)为了实现线程安全:该类的私有类引用成员,进行是否为null判断时 进行加锁
- 2)为了提高效率:只需要在第一次时进行判断;而不是每次都进入执行锁的代码块
- 双重保险
class Lazy {
private static Lazy lazy = null;
private Lazy() {}
public static Lazy getLazy() {
/* 该语句中的同步代码块,并不是每一次都需要执行,只需在没有创建该对象时才需要执行;
* 为了提高执行效率,可以增加一个外层的if判断
* 虽用到lazy共享资源,但并不会出现不同步的问题,因为里层锁中,还有一次是否为null的判断
*/
if(lazy==null) {
synchronized(Lazy.class) { //同步代码块
if(lazy == null)
lazy = new Lazy();
}
}
return lazy;
}
}