java单例模式详解
2016-04-07 15:42
399 查看
饿汉法
饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。代码如下:
缺点:无法实现对象延时加载。
懒汉法
懒汉式就是需要使用该类的时候再创建对象实例(进而实现了对象的延时加载,减少了系统负荷)。
1.单线程实现方式,代码如下:
缺点:线程不安全,如果有多条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。
2.线程安全方式,代码如下:
说明:使用volatile关键字进行限制,保证其对所有线程的可见性,并且禁止对其进行指令重排序优化。
缺点:每次调用getSingleton()方法,都会因为synchronized关键字进行等待,效率低下。
3.兼顾线程安全和效率方式,代码如下:
说明:“双重检查锁”,使用双判断null方式,可以减少线程进行等待,提高效率。
扩展:
方式2中说明:
1.[b]可见性:[/b]指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。(工作内存是线程独享的,主存是线程共享的);
2.重新排序:禁止指令重排序优化。我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同。这在单线程看起来没什么问题,然而一旦引入多线程,这种乱序就可能导致严重问题。volatile关键字就可以从语义上解决这个问题。(但是禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。)
静态内部类法
优点:静态内部类只有在使用的时候才会被加载,不会随主类的加载而加载,实现了延时加载,静态内部类只会被加载一次,保证了线程安全。
枚举写法
优点:防止用户使用反射方式调用私有构造器;提供了自动序列化机制,防止反序列化的时候创建新的对象。
饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。代码如下:
public class Singleton { private static Singleton = new Singleton(); private Singleton() {} public static getSignleton(){ return singleton; } }
缺点:无法实现对象延时加载。
懒汉法
懒汉式就是需要使用该类的时候再创建对象实例(进而实现了对象的延时加载,减少了系统负荷)。
1.单线程实现方式,代码如下:
public class Singleton { private static Singleton singleton = null; private Singleton(){} public static Singleton getSingleton() { if(singleton == null) singleton = new Singleton(); return singleton; } }
缺点:线程不安全,如果有多条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。
2.线程安全方式,代码如下:
public class Singleton { private static volatile Singleton singleton = null; private Singleton(){} public static Singleton getSingleton(){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } return singleton; } }
说明:使用volatile关键字进行限制,保证其对所有线程的可见性,并且禁止对其进行指令重排序优化。
缺点:每次调用getSingleton()方法,都会因为synchronized关键字进行等待,效率低下。
3.兼顾线程安全和效率方式,代码如下:
public class Singleton { private static volatile Singleton singleton = null; private Singleton(){} public static Singleton getSingleton(){ if(singleton == null){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } }
说明:“双重检查锁”,使用双判断null方式,可以减少线程进行等待,提高效率。
扩展:
方式2中说明:
1.[b]可见性:[/b]指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。(工作内存是线程独享的,主存是线程共享的);
2.重新排序:禁止指令重排序优化。我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同。这在单线程看起来没什么问题,然而一旦引入多线程,这种乱序就可能导致严重问题。volatile关键字就可以从语义上解决这个问题。(但是禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。)
静态内部类法
public class Singleton { private static class Holder { private static Singleton singleton = new Singleton(); } private Singleton(){} public static Singleton getSingleton(){ return Holder.singleton; } }
优点:静态内部类只有在使用的时候才会被加载,不会随主类的加载而加载,实现了延时加载,静态内部类只会被加载一次,保证了线程安全。
枚举写法
public enum Singleton { INSTANCE; private String name; public String getName(){ return name; } public void setName(String name){ this.name = name; } }
优点:防止用户使用反射方式调用私有构造器;提供了自动序列化机制,防止反序列化的时候创建新的对象。
相关文章推荐
- activiti自定义流程之Spring整合activiti-modeler5.16实例(九):历史任务查询
- activiti自定义流程之Spring整合activiti-modeler5.16实例(九):历史任务查询
- java使用数组实现顺序队列
- Spring MVC 入门示例讲解
- Spring3MVC 在JSP中使用@ModelAttribute--源自技术
- javasScript正则表达式验证密码(必须含数字字符特殊符号,长度4-16位之间)
- JavaMail使用SMTP协议发送电子邮件
- Eclipse中.xml , .propertise 为后缀的文件中文乱码
- [疯狂Java]SQL-DML:插入、修改、删除记录
- Java是编译型语言还是解释型语言
- /root/hadoop/bin/hdfs: line 204: /opt/jdk/bin/java: No such file or directory /root/hadoop/bin/hdfs:
- java解析ajax之json字符串
- only available on JDK 1.5 and higher
- springmvc常用注解与类型转换
- Project Lombok插件使用
- Java Map遍历
- Java笔试题分类总结--位操作
- 【Java并发编程四】关卡
- 【JAVA重温】String 类
- 如何给 eclipse 设置快捷键