详解JAVA 七种创建单例的方法
1饿汉式
publicclassSingleton1{ //不能延迟加载占用内存耗费资源 privatestaticSingleton1singleton1=newSingleton1(); publicstaticSingleton1getSingleton1(){ returnsingleton1; } }
可以保证多个线程下唯一实例,getSingleton1方法性能较高,但是无法进行懒加载。
2懒汉式
publicclassSingleton2{ //延迟加载 //多线程下不安全 privatestaticSingleton2singleton1=null; publicSingleton2getSingleton1(){ if(singleton1==null){ singleton1=newSingleton2(); } returnsingleton1; } }
懒汉式解决了延迟加载和资源问题,但是多线程下存在线程不安全问题。
3懒汉式+同步
publicclassSingleton3{ //延迟加载 //多线程下不安全 privatestaticSingleton3singleton1=null; //解决延迟加载多线程安全问题,但存在读操作,加锁问题,线程排队,写操作只有一次获取时需要排队等候问题 publicsynchronizedSingleton3getSingleton1(){ if(singleton1==null){ singleton1=newSingleton3(); } returnsingleton1; } /* 等同方法前加锁 publicstaticSingleton3getSingleton1(){ synchronized(Singleton3.class){ if(singleton1==null){ singleton1=newSingleton3(); } } returnsingleton1; } */ }
解决延迟加载多线程安全问题,但存在读操作,加锁问题,线程排队,写操作(创建对象)只有一次,但是获取时需要排队等候问题
4懒汉式+双重检验
publicclassSingleton4{ //延迟加载 privatestaticSingleton4singleton1=null; //解决读操作多线程情况下排队获取问题,但是双重校验也存在一个问题,jvm重排序的问题下会存在空指针问题 publicstaticSingleton4getSingleton1(){ if(singleton1==null){ synchronized(Singleton4.class){ if(singleton1==null){ singleton1=newSingleton4(); } } } returnsingleton1; } }
解决读操作多线程情况下排队获取问题,但是双重校验也存在一个问题,jvm重排序的问题下会存在空指针问题
但存在一个问题,jvm指令重排序,JVM的即时编译器中存在指令重排序的优化。
1首先给singleton1分配内存
2Singleton4执行构造函数开辟空间
3调用getSingleton1()方法创建对象
JVM的即时编译器中存在指令重排序的优化
理想情况下jvm执行顺序是123也可能是132,13在创建完对象后,再执行2返回null,此时就是空指针了。
5懒汉式+双重检验+volatile
volatile关键字禁止JVM编译时指令重排序
publicclassSingleton5{ //延迟加载 //volatile关键字禁止指令重排序 //解决双重校验也存在一个问题,jvm重排序的问题下会存在空指针问题 privatestaticvolatileSingleton5singleton1=null; publicstaticSingleton5getSingleton1(){ if(singleton1==null){ synchronized(Singleton5.class){ if(singleton1==null){ singleton1=newSingleton5(); } } } returnsingleton1; } }
6静态内部类
publicclassSingleton6{ //延迟加载 //静态内部类静态的始终在jvm中存在一份 staticclassSingleton{ privatestaticSingleton6singleton1=newSingleton6(); } publicstaticSingleton6get(){ returnSingleton.singleton1; } }
7枚举
publicclassSingleton7{ //枚举类型是线程安全构造方法只会被装载一次 privateenumSingleton{ Singleton; privatefinalSingleton7singleton7; Singleton(){ singleton7=newSingleton7(); } publicSingleton7getSingleton7(){ returnsingleton7; } } //延迟加载 publicstaticSingleton7get(){ returnSingleton.Singleton.getSingleton7(); } //测试 publicstaticvoidmain(String[]args){ IntStream.rangeClosed(1,100).forEach(i->{ newThread(String.valueOf(i)){ @Override publicvoidrun(){ System.out.println(Singleton7.get()); } }.start(); }); } }
枚举类型不允许被继承,但线程是安全的,只能被实例化一次,但是枚举类型不能够懒加载,和方法配合使用,调用get()静态方法,然后singleton7会延迟加载得到实例化。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。