我理解的java设计模式之单例模式

6 篇文章 0 订阅
3 篇文章 0 订阅

单例模式: 单例模式的意图是保证单例类在系统中有且仅有一个实例存在。
直接上代码看一下

/**
* 单例模式饿汉式
* static修饰,随类的加载而加载,只加载一次,天生就是线程安全的
* 缺点:没有lazy loading的效果,从而降低内存的使用率
* @author lz
*
*/
public class Singleton {
private static Singleton instance=new Singleton();
private Singleton(){}//将构造器私有
public static Singleton getgetInstance(){
return instance;
}
}

//———————单例模式饿汉式end——————————————

/**
* 单例模式懒汉式
* 只适合单线程模式,只有当使用时才会创建
* @author lz
*
*/
class Singleton2 {
private static Singleton2 instance2=null;
private Singleton2(){}//将构造器私有
public static Singleton2 getgetInstance(){
if(instance2 == null){
instance2=new Singleton2();
}
return instance2;
}
}

//———————-单线程下的懒汉式end—————————————–

/**
* 单例模式懒汉式
* 多线程下,缺点:getInstance方法得到singleton实例的时候都有一个试图去获取同步锁的过程,很耗时的
* @author lz
*
*/
class Singleton3 {
private static Singleton3 instance3=null;
private Singleton3(){}//将构造器私有
public static synchronized Singleton3 getgetInstance(){
if(instance3 == null){
instance3=new Singleton3();
}
return instance3;
}
}

//——————加同步的懒汉式end———————————————

/**
* 单例模式懒汉式
* 多线程下,改良版,只有当instance为null时,需要获取同步锁,创建一次实例。当实例被创建,则无需试图加锁
* @author lz
*
*/
class Singleton4 {
private static Singleton4 instance4=null;
private Singleton4(){}//将构造器私有
public static Singleton4 getgetInstance(){
if(instance4 == null){
synchronized (Singleton4.class) {
if(instance4 == null){
instance4=new Singleton4();
}
}
}
return instance4;
}
}
/**
*
* 解决双重检查的缺点
* 防止反序列化和反射创建多个单列
*
* @author lz
*
*/
class Singleton8 implements Serializable{

private static final long serialVersionUID = 1L;

private static Singleton8 instance8=null;
private static int flgs=1;
private Singleton8(){
    /** 
     * 防止反射攻击,只运行调用一次构造器,第二次抛异常 
     */  
    if(flgs==1){  
        flgs++;  
    }else{  
        throw new RuntimeException("只能调用一次构造函数");  
    }  
    System.out.println("调用Singleton的私有构造器");  
}
/** 
 * 用同步代码块的方式,在判断单例是否存在的if方法里使用同步代码块,在同步代码块中再次检查是否单例已经生成, 
 * 这也就是网上说的 双重检查加锁的方法 
 * @return 
 */  
public static synchronized Singleton8 getInstance(){  
    if(instance8==null){  
        synchronized (Singleton8.class) {  
            if(instance8==null){  
                instance8 = new Singleton8();  
            }  
        }  
    }  
    return instance8;  
}  
/** 
 *  
 * 防止反序列生成新的单例对象
 * 序列化操作提供了一个很特别的钩子(hook)-类中具有一个私有的被实例化的方法readresolve(),
 * 这个方法可以确保类的开发人员在序列化将会返回怎样的object上具有发言权
 * 这样当JVM从内存中反序列化地"组装"一个新对象时,就会自动调用这个 readResolve方法来返回
 * 我们指  定好的对象了, 单例规则也就得到了保证.
 * 详解http://www.javalobby.org/java/forums/t17491.html
 * @return 
 */  
private Object readResolve()throws ObjectStreamException{  
    return instance8;  
}

}
//——————加双重检查机制的懒汉式end———————————————

/**
* 单例模式懒汉式
* 多线程下,在改良,上面的双重的if总是不提倡的。静态内部类的方式
* 当调用静态内部类时,将创建这个instance5 并且因为是static只创建一次
* classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗
* https://www.oschina.net/question/2273217_217864 这里是静态内部类加载顺序的问题
* @author lz
*
*/
class Singleton5 {

private Singleton5(){}//将构造器私有

//使用静态内部类
private static class Inner{
    private static final Singleton5 instance5=new Singleton5();
}
public static  Singleton5 getgetInstance(){
    return Inner.instance5;
}

}

/**
* 静态内部类的缺点修补
* @author lz
*
*/
class Singleton9 implements Serializable{
private static final long serialVersionUID = 6397008420924619156L;
private static int flags=1;
private Singleton9(){//将构造器私有,防止反射
if(flags==1){
flags++;
}else{
throw new RuntimeException(“只能运行一次”);
}
System.out.println(“调用Singleton的私有构造器”);
}

//使用静态内部类
private static class Inner{
    private static final Singleton9 instance9=new Singleton9();
}

public static  Singleton9 getgetInstance(){
    return Inner.instance9;
}

/** 
 *  
 * 防止反序列生成新的单例对象
 * 序列化操作提供了一个很特别的钩子(hook)-类中具有一个私有的被实例化的方法readresolve(),
 * 这个方法可以确保类的开发人员在序列化将会返回怎样的object上具有发言权
 * 这样当JVM从内存中反序列化地"组装"一个新对象时,就会自动调用这个 readResolve方法来返回
 * 我们指定好的对象了, 单例规则也就得到了保证.
 * 详解http://www.javalobby.org/java/forums/t17491.html
 * @return 
 */  
private Object readResolve()throws ObjectStreamException{  
    return Inner.instance9;  
}

}
//————————–静态内部类的方式end————————————————

/**
* 枚举实现
* 上面的双重检查和静态内部类的形式缺点:
* 都需要额外的工作(Serializable、transient、readResolve())来实现序列化,*
* 否则每次反序列化一个序列 化的对象实例时都会创建一个新的实例。
* 可能会有人使用反射强行调用我们的私有构造器(如果要避免这种情况,可以修改构造器,
* 让它在创建第二个实例的时候抛异常)。
* 枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象
* http://www.cnblogs.com/yangzhilong/p/6148639.html 这里有介绍
* @author lz
*
*/
enum Singleton7{
instance;
public void whateverMethod(){}
}

/**
* 登记式单例,供参考 copy的
* http://blog.csdn.net/jason0539/article/details/23297037/
*
*/


最后,不管采取何种方案,请时刻牢记单例的四大要点:
线程安全
延迟加载
序列化与反序列化安全
反射

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值