保证一个类仅有一个实例,并提供一个全局的访问点。
类型:创建型
使用场景:确保任何情况下绝对仅有一个实例
线程池、数据库连接池
优点:仅有一个实例,减少内存开销
避免对资源文件多重占用
严格控制访问
缺点:无接口,拓展困难
重点:私有构造器、线程安全、延迟加载、序列化和反序列化安全、反射攻击
单例模式:懒汉式、饿汉式
public class LazySingleton {
/**
* 初始化懒加载
*/
private static LazySingleton lazySingleton = null;
/**
* 私有构造方法
*/
private LazySingleton(){
}
/**
* 静态方法public方法,获得实例
* @return lazySingleton
*/
public static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
单线程可用,但多线程会破坏单例契约,线程不安全
public class LazySingletonTest {
/**
* 检测线程是否安全
*/
public static void main( String[] args ) {
// LazySingleton lazySingleton = new LazySingleton(); 私有构造方法无法创建实例
Thread t1 = new Thread( new T() );
Thread t2 = new Thread( new T() );
t1.start();
t2.start();
System.out.println("Program End...");
}
}
public class T implements Runnable {
@Override
public void run() {
LazySingleton lazySingleton = LazySingleton.getInstance();
System.out.println(Thread.currentThread().getName()+ " "+lazySingleton);
}
}
Debug调试,令两个线程都溜入该单例模式的20行中,闷声发大财。两个线程均产生各自的对象
Thread-0 singleton.LazySingleton@15082754
Thread-1 singleton.LazySingleton@16fea746
Program End...
改进:在方法中添加synchronized,锁定整个类,当一个线程创建单例时,会阻塞其他线程进入该类
synchronized:
public synchronized static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
public static LazySingleton getInstance(){
synchronized(LazySingleton.class){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
}
return lazySingleton;
}
public class LazyDoubleCheckSingleton {
/**
* volatile解决由重排序而产生的空指针异常,volatile中不允许重排序
*/
private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){
}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton == null){
synchronized ( LazyDoubleCheckSingleton.class ){
if(lazyDoubleCheckSingleton == null){
/*
* 1.给对象分配内存
* 2.初始化对象
* 3.设置lazyDoubleCheckSingleton指向刚分配的内存地址
* 所有线程在执行java程序时必须要遵守intra-thread semantics
* 保证重排序不会改变单线程内的排序结果
*
*/
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
性能优化:
public class StaticInnerClassSingleton {
/**
* 私有构造方法
*/
private StaticInnerClassSingleton(){
}
/**
* 静态内部类
*/
private static class InnerClass{
private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
/**
* 获取方法
* @return Instance
*/
public static StaticInnerClassSingleton getInstance(){
return InnerClass.staticInnerClassSingleton;
}
}
原理:
饿汉式单例模式:类加载时就初始化完成,可以用final修饰,可用静态代码块的方式创建实例
public class HungrySingleton {
/**
* 创建实例,直接初始化
*/
// private static final HungrySingleton hungrySingleton = new HungrySingleton();
private static final HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
/**
* 构造方法私有
*/
private HungrySingleton(){
}
/**
* 单例方法
*/
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
序列化和反序列化破坏单例模式
反射破坏单例模式:无参构造方法的反射破坏——懒汉式无法防御
反射防御
枚举类实现单例模式
原文:https://www.cnblogs.com/xm08030623/p/12036225.html