单例模式

来源:互联网 发布:淘宝未收货退款 编辑:程序博客网 时间:2024/05/16 10:48

Inspired by Effective Java.

Singleton模式是在编程实践中应用最广泛的几种设计模式之一。以前知道的,实现单例的方法有两种(下面的A、B)。刚刚在读《Effective Java的时候》学到一种新的更好的方法(E):单元素的枚举类型。同时通过网上资料也知道了其他两种方法(C、D)。最后一种在Java中从1.5版本开始支持,其他语言在验证后说明。

A.饿汉式(类加载的时候就创建实例)。
代码如下:

public class MaYun {
public static final Mayun instance = new Mayun(); //静态的final的MaYun
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.instance.splitAlipay();

Feature:可以通过反射机制攻击;线程安全[多个类加载器除外]。

A+.饿汉变种[推荐]

public class MaYun {
private static Mayun instance = new Mayun();
private static getInstance() {
return instance;
}
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

A++.饿汉变种(类初始化的时候实例化instance):

public class MaYun {
private MaYun instance = null;
static {
instance = new MaYun();
}
private MaYun() {
//MaYun诞生要做的事情
}
public static MaYun getInstance() {
return this.instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

B.懒汉式。
代码如下:

public class MaYun {
private static MaYun instance = null;
private MaYun() {
//MaYun诞生要做的事情
}
public static MaYun getInstance() {
if (instance == null) {
instance = new MaYun();
}
return instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.getInstance().splitAlipay();

Feature:延时加载;线程不安全,多线程下不能正常工作;需要额外的工作(Serializable、transient、readResolve())来实现序列化。

B+.懒汉式变种。

public class MaYun {
private static MaYun instance = null;
private MaYun() {
//MaYun诞生要做的事情
}
public static synchronized MaYun getInstance() {
if (instance == null) {
instance = new MaYun();
}
return instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

Feature:线程安全;效率比较低,因为需要线程同步的时候比较少。

C.静态内部类[推荐]。
代码如下:

public class MaYun {
private static class SigletonHolder {
private static final instance = new MaYun();
}
public static final getInstance() {
return SigletonHolder.instance;
}
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
Call:MaYun.getInstance().splitAlipay();

Feature:线程安全;延迟加载。

D.双重校验锁[不推荐]。
代码如下:

public class MaYun {
private volatile static MaYun instance;
private MaYun (){}
public static MaYun getInstance() {
if (instance == null) {
synchronized (MaYun.class) {
if (instance == null) {
instance = new MaYun();
}
}
}
return instance;
}
}

Feature:jdk1.5之后才能正常达到单例效果。

E.编写一个包含单个元素的枚举类型[极推荐]。
代码如下:

public enum MaYun {
himself; //定义一个枚举的元素,就代表MaYun的一个实例
private String anotherField;
MaYun() {
//MaYun诞生要做的事情
//这个方法也可以去掉。将构造时候需要做的事情放在instance赋值的时候:
/** himself = MaYun() {
* //MaYun诞生要做的事情
* }
**/
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.himself.splitAlipay();

Feature:从Java1.5开始支持;无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。

总之,五类:懒汉,恶汉,双重校验锁,静态内部类,枚举。
恶汉:因为加载类的时候就创建实例,所以线程安全(多个ClassLoader存在时例外)。缺点是不能延时加载。
懒汉:需要加锁才能实现多线程同步,但是效率会降低。优点是延时加载。
双重校验锁:麻烦,在当前Java内存模型中不一定都管用,某些平台和编译器甚至是错误的,因为instance = new MaYun()这种代码在不同编译器上的行为和实现方式不可预知。
静态内部类:延迟加载,减少内存开销。因为用到的时候才加载,避免了静态field在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。
枚举:很好,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。但是失去了类的一些特性,没有延迟加载,用的人也太少了~~

以后多推广推广单元素枚举这种更好的单例实现方式。在项目中的代码开始修改实施

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 信用卡暂时不用怎么办 blued下载不了怎么办 文件格式错误怎么办 错误码2611003怎么办 优惠券被天猫吞了怎么办 鞋子放鞋盒发霉怎么办 蘑菇街登不上怎么办 桑蚕丝衣服皱褶怎么办 羊毛衫会扎人怎么办 肌肉腿外翻怎么办 大腿赘肉怎么办 淘宝卖家不举证怎么办 咸鱼收到假货怎么办 伤没钱看病怎么办 steam付款失败怎么办 配偶没有公积金怎么办 玩吃鸡配置不够怎么办 华为AL20黑屏怎么办 华为照片不见了怎么办 电话卡暂停服务怎么办 电脑屏幕居中了怎么办 冰箱霜太多怎么办 qq账号忘了怎么办没有邮箱怎么办 车祸赔不起怎么办对方天天闹怎么办 专家解读有口臭怎么办口气重怎么办 油锅起火时应该怎么办或者怎么办 淘宝买了东西想改地址怎么办怎么办 手机显示程序异常这是怎么办怎么办 钢笔笔尖坏了怎么办 陶瓷刀钝了怎么办 地下城fps低怎么办 床头只能朝西怎么办 钢笔笔尖歪了怎么办 钢笔笔尖漏墨怎么办 被蜈蚣咬了怎么办 信用卡被盗刷了怎么办 练太极拳膝盖痛怎么办 僵尸毛毛虫咬了怎么办 迅雷下载速度慢怎么办 驾驶证换证过期怎么办 发生地震时该怎么办