单例模式
2016-07-21 17:59
288 查看
基本上做程序的都知道单例模式,那么为什么要用单例模式了?
首先单例模式有几个关键点
1 构造函数不对外开放,一般为Private;(通过构造函数私有化,使得客户端代码不能通过new 的形式手动构造单例类的对象) 《在这就不能多次构建对象》
2 通过一个静态方法或者枚举返回单例类对象(客户端只能通过这个静态)
3 确保单例类的对象有且只有一个,尤其在多线程环境下 (明确多线程为什么会出现多个对象,因为虚拟机在分配线程的时候允许执行器乱序执行)(JVM 执行写的代码的是会把一个代码编译成多条汇编指令,然后乱序执行)
例如: String str = new String();
会执行大致3件事
1 给String 的实例分配对象
2 调用String() 的构造函数
3 江 str 对象指向分配的内存空间(此时Str 就不是null 了)
(执行顺序 可以是 1-2-3 也可以是 1-3-2)(JVM 1.5以后 官方修改了BUG 用了 volatile关键字)
4 确保单例类对象在反序列化时候不会重新构建对象
常见的几种单例模式
饿汉式(饿了就先吃,先创建对象)
public class A {
private static final A a = new A();
private A(){
}
private static A getA(){]
return a;
}
}
懒汉式
public class A {
private static A a ;
private A(){
}
private static syncyronized A getA(){
if(a == null){
a = new A ();
}
return a;
}
}
饿汉是线程安全的(没有在使用的时候就创建对象) 懒汉是线程不安全的所以得加同步锁 (备注 : 每次调用方法的时候使用同步锁会消耗不必要的资源,反应慢不建议使用 懒汉模式)
3 Double Check Lock (DCL) 实现单例
DCL 实现单例模式的有点是能够在需要的时候才创建对象 有能百战线程安全 且单例对象的时候可以不进行同步锁
优点 资源利用高 第一次执行getA 的时候才会被实例化 效率高 缺点 第一次加载的时候有点慢 也由于java 内存模型的原因偶尔会失败,在高发的环境下也有可能失败
public class A {
private static A a = null ;
private A(){
}
private static syncyronized A getA(){
if(a == null){
synchronized ( A.class){
if(a == null){
a = new A();
}
}
a = new A ();
}
return a;
}
}
4 静态内部类单例模式
这种方法在第一次加载类的时候并不会创建对象 只有第一次调用 getA 的时候才会导致虚拟机加载A 类 这种方式即保证对象的唯一性还能延迟单例的实力话
public class A {
private A(){
}
private static A getA(){
return AHolder.aHolder;
}
private static class AHolder{
private static final AHolder aHolder = new AHolder();
}
}
5 推介使用的 枚举单例
枚举 最大的有点 默认创建的线程是安全的 并且在任何情况下都是单例
public enum A {
INSTANCE;
public void doSometing(){
}
}
首先单例模式有几个关键点
1 构造函数不对外开放,一般为Private;(通过构造函数私有化,使得客户端代码不能通过new 的形式手动构造单例类的对象) 《在这就不能多次构建对象》
2 通过一个静态方法或者枚举返回单例类对象(客户端只能通过这个静态)
3 确保单例类的对象有且只有一个,尤其在多线程环境下 (明确多线程为什么会出现多个对象,因为虚拟机在分配线程的时候允许执行器乱序执行)(JVM 执行写的代码的是会把一个代码编译成多条汇编指令,然后乱序执行)
例如: String str = new String();
会执行大致3件事
1 给String 的实例分配对象
2 调用String() 的构造函数
3 江 str 对象指向分配的内存空间(此时Str 就不是null 了)
(执行顺序 可以是 1-2-3 也可以是 1-3-2)(JVM 1.5以后 官方修改了BUG 用了 volatile关键字)
4 确保单例类对象在反序列化时候不会重新构建对象
常见的几种单例模式
饿汉式(饿了就先吃,先创建对象)
public class A {
private static final A a = new A();
private A(){
}
private static A getA(){]
return a;
}
}
懒汉式
public class A {
private static A a ;
private A(){
}
private static syncyronized A getA(){
if(a == null){
a = new A ();
}
return a;
}
}
饿汉是线程安全的(没有在使用的时候就创建对象) 懒汉是线程不安全的所以得加同步锁 (备注 : 每次调用方法的时候使用同步锁会消耗不必要的资源,反应慢不建议使用 懒汉模式)
3 Double Check Lock (DCL) 实现单例
DCL 实现单例模式的有点是能够在需要的时候才创建对象 有能百战线程安全 且单例对象的时候可以不进行同步锁
优点 资源利用高 第一次执行getA 的时候才会被实例化 效率高 缺点 第一次加载的时候有点慢 也由于java 内存模型的原因偶尔会失败,在高发的环境下也有可能失败
public class A {
private static A a = null ;
private A(){
}
private static syncyronized A getA(){
if(a == null){
synchronized ( A.class){
if(a == null){
a = new A();
}
}
a = new A ();
}
return a;
}
}
4 静态内部类单例模式
这种方法在第一次加载类的时候并不会创建对象 只有第一次调用 getA 的时候才会导致虚拟机加载A 类 这种方式即保证对象的唯一性还能延迟单例的实力话
public class A {
private A(){
}
private static A getA(){
return AHolder.aHolder;
}
private static class AHolder{
private static final AHolder aHolder = new AHolder();
}
}
5 推介使用的 枚举单例
枚举 最大的有点 默认创建的线程是安全的 并且在任何情况下都是单例
public enum A {
INSTANCE;
public void doSometing(){
}
}
相关文章推荐
- 快速编写“专家级”makefile(2.创建基本编译环境-使用功能”函数“)
- 百度UEditor编辑器使用教程与使用方法
- SQLServer 2008数据库查看死锁、堵塞的SQL语句
- jasperReport和JasperServer的使用实例
- ORM 框架之 greenDAO 使用心得
- MYSQL中的基本操作
- UVALive 2052 Number Steps【简单模拟】水题
- SecureCRT乱码解决方案
- CodeForces 612B HDD is Outdated Technology
- Leetcode 225. Implement Stack using Queues (Easy) (cpp)
- 快速编写“专家级”makefile(2.创建基本编译环境)
- AndroidManifest.xml官方介绍
- java网络编程:通过HTTPS协议传送xml文件交互
- CountDownTimer手机短信计时器的使用
- Android 自定义ViewGroup 实战篇 -> 实现FlowLayout
- 高效加载图片,避免OOM
- LeakCanary 实用的内存泄露自动探测工具
- BBB 使用串口
- Android 混淆总结(直接copy)
- 北斗系统基础知识0(专家解析:北斗卫星导航通信系统起源与发展工作原理)