概述
单例,从名字上面就可以看出来,首先他肯定是一个类实例,然后他同时只能允许一个访问,那么这样才构成了一个单例,单例模式在我们实际开发中应用非常广泛,比如我们创建了一个数据库连接池,然后又创建了一个工具类把这个连接池与线程进行绑定,那么我们就可以实现基于线程来实现对事务管控,数据库连接是多次的,但是基于连接管控的线程只有一个,那么这个工具类就可以构造成一个单例模式,单例模式实现方式有多种,我这里就介绍一下最基础的饿汉式以及增强懒汉式,双重效验锁,简单明了并且足于应付大部分的开发工作。
饿汉式
顾名思义,他就是一个饿汉,不管是什么情况,首先他在系统类加载的时候自己就new了一个对象出来,然后当有调用他的时候,他就直接使用这个对象,饿汉式在初始化的时候就加载了,像上面用到的线程工具类,管理数据库连接池,那么这个用饿汉就非常适合。
/**
-
单例:饿汉模式 立即加载
-
@author fangyf
/
public class HungrySingleton {
/*- 将方法私有
/
private HungrySingleton() {
}
/* - 将自身实例化对象设置一个属性,并用final static修饰
*/
private final static HungrySingleton hungrySingleton = new HungrySingleton();
public static HungrySingleton getInstance(){
return hungrySingleton;
}
/**- 方法
*/
public void singletonRun() {
System.out.println(“单例:饿汉模式开启。”);
}
}
- 将方法私有
懒汉式 双重校验锁
使用饿汉式确实很省事,而且他是线程安全的,什么也不用考虑,但是如果所有单例对象都使用饿汉,那么在我们系统初始化的时候,那么对这些对象进行实例化的时候,遇到复杂对象,构建就会非常慢,影响程序启动,所以一些非必要的单例对象,这时候就考虑要使用懒汉式,及判断对象是否为空,如果为空即开始用时才创建对象,但是这里就又涉及到线程安全问题,通常解决办法是在方法上加synchronized关键字锁住整个方法,其实他不是最优解,因为如果对象存在,不需要创建,他还是要在方法外排队,消耗时间,因此就诞生了双重效验锁。
/**
-
单例:懒汉模式 双重校验锁
-
@author fangyf
/
public class LazySingleton {
/*- 将自身实例化对象设置一个属性,并用static修饰,增加volatile关键字修饰防止CPU指令重排,影响线程安全
*/
private volatile static LazySingleton lazySingleton;
/**
- 构造方法私有化
*/
private LazySingleton() {
}
/**
- 静态方法返回该实例,加synchronized关键字实现同步
- @return
/
public static LazySingleton getInstance(){
//不加锁情况下第一次判断
if(lazySingleton == null){
synchronized(LazySingleton.class){
//第二次判断 如果还为空 创建对象
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
/* - 方法
*/
public void singletonRun() {
System.out.println(“单例:双重校验锁懒汉模式开启。”);
}
}
- 将自身实例化对象设置一个属性,并用static修饰,增加volatile关键字修饰防止CPU指令重排,影响线程安全