详解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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。