单例模式(Singleton Pattern)
是指确保一个类在任何情况下都绝对只有一个实例
私有化构造方法,属于创建型模式(结构型模式/行为型模式)
1.饿汉式单例
不管使用使用到,在类加载是进行创建
缺点:浪费空间
public class HungrySingleton{
//私有静态不可覆盖变量
private static final HungrySingleton hungrySingleton;
//类加载时创建类实例
static{
hungrySingleton = new HungrySingleton();
}
//私有化构造方法
private HungrySingleton(){}
//静态获取实例方法
public static HungrySingleton getInstace(){
return hungrySingleton;
}
}
2.懒汉式单例
类加载是并不初始化,第一次使用时进行初始化
public class LazySingleton{
//私有静态变量,默认为空
private static LazySingleton lazySingleton=null;
//私有化构造方法
private HungrySingleton(){}
//静态获取实例方法,线程不安全实例可能会多次被创建
public static LazySingleton getInstace(){
if(lazySingleton == null){
lazySingleton = new lazySingleton();
}
return lazySingleton;
}
}
3.注册式单例
即:内部类模式单例(性能最优)
public class LazyInnerClassSingleton{
//私有化构造方法
private LazyInnerClassSingleton(){
//防止反射破解
if(LazyHolder.LAZY != null){
throw new Exception("不允许构建多个实例");
}
}
//静态获取实例方法,线程安全
//①懒汉式加载
//②LazyHoler中的逻辑,当getInstace被调用时候才知晓
//③巧妙的运用了内部类的特性,JVM底层逻辑.完美的避免了线程安全问题
public static fianl LazyInnerClassSingleton getInstace(){
return LazyHolder.LAZY;
}
//防止序列化->反序列化对象破解单例
private Object readResolve(){
return LazyHolder.LAZY
}
//内部类
private static class LazyHolder{
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
//反射破解
public class Test{
public static void main(String[] args0){
try{
Class<?> clazz = LazyInnerClassSingleton.class;
java.lang.reflect.Conotructor c = clazz.getDeclaredConotructor(null);
c.setAccessible(true);
c.newInstance();
}catch(Exception e){
e.printStackTrace();
}
}
}
3.1枚举式(注册式的一种)
/**
* Description:数据库连接(被单例对象)
*
* @date 2019-05-09 16:23
*/
public class DBConnection {
}
/**
* Description:数据源枚举
*
* @date 2019-05-09 16:10
*/
public enum DataSourceEnum {
DATASOURCE;
private DBConnection dbConnection;
public DBConnection getDbConnection() {
return dbConnection;
}
public static DataSourceEnum getInstance(){
return DATASOURCE;
}
DataSourceEnum() {
this.dbConnection = new DBConnection();
}
}
/**
* Description:测试
*
* @date 2019-05-09 16:14
*/
public class Test {
public static void main(String[] args) {
DBConnection con1 = DataSourceEnum.DATASOURCE.getDbConnection();
DBConnection con2 = DataSourceEnum.DATASOURCE.getDbConnection();
System.out.println(con1 == con2);
}
}
原理
3.2容器式单例
① 私有化构造方法
②定义线程安全的容器(ConcurrentMap)
③获取对象时,先从容器内取,存在容器内直接返回;不出存在通过反射获取对象放入容器后进 行返回,注意线程安全问题,需要解决
3.3.ThreadLocal单例
伪线程安全:全局线程不安全,线程内线程安全
public class Apple{
private Apple(){}
private static final ThreadLocal<Apple> threadLocalInstance = new ThreadLocal<Apple>(){
@Override
protected Apple initiaValue(){
return new Apple();
}
}
public static Apple getInstance(){
threadLocalInstance.get();
}
}