核心作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
实例:
1.Windows中的任务管理器 2.回收站……
优点:
只生成一个实例,减小了系统性能的开销
五种单例模式的实现方式:
1、饿汉式(线程安全,调用效率高。但是,不能延时加载)
私有属性static类变量 先初始化(new 新对象)
私有的构造器
开放的方法--->取对象(方法无同步)
public class Demo01 {
//类初始化时,立即加载这个对象。(没有延时加载优势)
//天然线程安全
private static Demo01 instance = new Demo01();
private Demo01(){}
//方法没有同步,调用效率高
public static Demo01 getInstance(){
return instance;
}
}
2、懒汉式(线程安全,调用效率不高。但是,可以延时加载)
私有属性static类变量 不用初始化
私有化构造器
开放方法-->取对象 使用方法时才检查初始化对象(new) (方法有同步)
public class Demo02 {
//类初始化时,不初始化这个对象。(延时加载优势)
//天然线程安全
private static Demo02 instance ;
private Demo02(){}
//方法同步,调用效率不高
public static synchronized Demo02 getInstance(){
if(instance==null){
instance = new Demo02();
}
return instance;
}
}
3、双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
将同步内容放到下方的if内部
public class Demo03 {
private Demo03(){}
private static Demo03 instance=null;
public static Demo03 getInstance() {
if (instance == null) {
Demo03 sc;
synchronized (Demo03.class) {
sc = instance;
if (sc == null) {
synchronized (Demo03.class) {
if(sc == null) {
sc = new Demo03();
}
}
instance = sc;
}
}
}
return instance;
}
}
4、静态内部类式(线程安全,调用效率高,但是,可以延时加载)
外部类没有static属性,不会像饿汉式那样立即加载对象
只有真正调用getInstance(),才会加载静态内部类。
public class Demo04 {
private static class SingleTonClassInstance{
private static final Demo04 instance = new Demo04();
}
public static Demo04 getInstance(){
return SingleTonClassInstance.instance;
}
private Demo04(){}
}
5、枚举单例(线程安全,调用效率高,不能延时加载)
基于JVM实现的
可以天然防止反射和反序列化漏洞
public enum Demo05 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
……
}
}
需要延时加载:静态内部类好于饿汉式
不需要延时加载:静态内部类好于懒汉式
测试懒汉式单例模式(如何防止反射和反序列化漏洞):
public class Demo06 implements Serializable{
//类初始化时,不初始化这个对象。(延时加载优势)
//天然线程安全
private static Demo06 instance ;
private Demo06(){
//通过这样防止反射创建新的对象
if(instance!=null){
throw new RuntimeException();
}
}
//方法同步,调用效率不高
public static synchronized Demo06 getInstance(){
if(instance==null){
instance = new Demo06();
}
return instance;
}
//反序列化时,如果定义了readResolve()方法则直接返回方法指定对象。而不再单独创建新的对象
private Object readResolve() throws ObjectStreamException{
return instance;
}
}