饿汉单例模式
“饿汉单例模式”,顾名思义就是就是比较饥饿的单例,迫切需要吃东西(额,这样形容好别扭…),so,需要第一时间给该“饿汉”准备吃的,运用在代码中就是需要在类加载的时候就创建了单例对象,代码如下:
public class HungerSingleton {
//饿汉单例模式在类加载的时候创建了单例对象
private static HungerSingleton hungerSingleton = new HungerSingleton();
private HungerSingleton(){
System.out.println("饿汉单例模式");
}
public HungerSingleton getHungerSingleton(){
//此时返回的为类加载时创建的单例对象
return hungerSingleton;
}
}
懒汉单例模式
“懒汉单例模式”,懒汉的意思是超级懒,犯有严重的拖延症,如果不是迫切的需要是不会去创建实例的,在类加载的时候不会主动去创建实例,会在第一次调用getInstance的时候去创建实例,这种技术又称为延迟加载技术,为避免多个线程同时调用getInstance的方法创建实例,需要加上关键字synchronized,代码如下:
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){
}
//synchronized避免多个线程同时调用该方法,创建多个实例
synchronized public LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
以上代码解决了多线程访问的线程安全问题,但是如果系统访问量较大,每次调用getInstance方法时都需要进行线程锁定判断,那系统的性能将会大大的降低,那我们该怎么进行优化呢?仔细梳理代码,可以发现其实我们无需对整个getInstance()方法进行锁定,只需要对lazySingleton = new LazySingleton()进行线程锁定即可,因此我们可以如下修改代码:
public LazySingleton getInstance(){
if(lazySingleton == null){
synchronized (LazySingleton.class){
lazySingleton = new LazySingleton();
}
}
return lazySingleton;
}
那这样修改以后就不会再有问题了吧,但是还有一种情况,就是线程a和线程b同时进入了getInstance方法里,此时线程a和线程b均能通过lazySingleton == null的判断,由于线程锁的缘故,a线程先进入了synchronized 锁定的代码进行实例的创建,但是线程a创建完实例后,线程b并不知道实例已经创建,还在傻傻的继续执行实例创建的代码,这样就出现问题了,就会存在创建了多个lazySingleton实例的情况,新问题就出现了,那我们该如何解决呢?当线程a创建好实例以后,再进行一次实例非空判断,此方法又叫双重检查锁定,具体代码实现如下:
private volatile static LazySingleton lazySingleton = null;
private LazySingleton(){
}
//synchronized避免多个线程同时调用该方法,创建多个实例
public LazySingleton getInstance(){
//第一重判断
if(lazySingleton == null){
synchronized (LazySingleton.class){
//第二重判断
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
请注意:如果通过双重检查锁定技术来实现懒汉模式,则需要在静态成员变量前面加上关键字volatile,被volatile修饰的成员变量可以确保多个线程都能正确处理,且改代码只能在JDK1.5及以上才能正确处理,volatile会屏蔽java虚拟机所做的一些代码优化,可能会导致系统性能的降低。
比较:
1.饿汉模式在类加载的时候就会创建实例,因此无需考虑多线程带来的影响,而且可以确保实例的唯一性,因此从调用速度和反应时间方面来讲会优于懒汉模式,但是由于无论该实例是否被使用都会被创建,相应的会出现资源浪费的情况,从资源利用来考虑懒汉模式会优于饿汉模式;
2.懒汉单例类在第一次使用时创建,因此不会一直占用资源,但需要处理好多线程问题,否则可能会出现创建多个实例的现象,还有就是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的机率变得较大,需要通过双重检查锁定等机制进行控制,这将导致系统性能受到一定影响。
2693

被折叠的 条评论
为什么被折叠?



