Java中的单例设计模式

Java中一共有23种设计模式,而单例设计模式作为其中最常见的一种,主要是为了解决一个类在内存中只存在唯一的对象或实例,其写法主要有两种:懒汉式单例(4种)、饿汉式单例

单例设计模式的实现:
①将类中的构造函数私有化,避免其他类中可以创建该类对象
②在本类中创建一个该类对象,进行实例化过程
③提供共有的静态方法供其他类来使用


1、饿汉式单例
在类加载,初始化的时候,单例对象便一起创建,占用了内存,但不存在线程安全问题

public class Sington {

    private static final Sington instance = new Sington(); 
    private Sington(){
    }
    public static Sington getInstance(){
        return instance;
    }
    public void loadData(){
        System.out.println("singleton data....");
    }
}

2、懒汉式单例
类加载初始化的时候没有创建其实例对象,只有当调用getIntance()方法的时候,才会去实例化这个对象,提高了内存使用效率

 public class Sington {

    private static  Sington instance = null;

    private Sington(){
    }
    public static Sington getInstance(){
        if(instance == null){
            instance = new Sington();
        }
        return instance;
    }
}

但上述实现单例的过程,存在这样的一种问题,当开启多线程来访问这个类对象,假设有两个线程A和B,当线程A执行到instance = new Sington() ,正在申请内存分配,可能需要0.001us,可就在这段时间内,线程B执行到 if(instance == null) ,这时条件为true,线程B继续往下执行,内存中便有了两个Sington 对象,出现了线程安全问题,为了解决这样的问题,一般我们采用以下四种方式来编写:

①在getInstance()方法上加同步,上this对象锁,保证线程之间互斥,但也因为锁对象影响了该方法的执行效率,毕竟大多数业务情况下是不存在并发执行的。

public class Sington {

    private static  Sington instance = null;

    private Sington(){
    }
    public synchronized static Sington getInstance(){
        if(instance == null){
            instance = new Sington();
        }
        return instance;
    }
}

②采用同步代码块+双重判断+votatile关键字保证线程安全,保证只有第一次进来的时候才会有同步锁,提高了效率,同时这里说一下多线程操作同一变量时,共享变量的安全性问题:多个线程在访问一个全局共享变量时,会先把变量从主存中加载到线程各自的工作内存中,然后在工作内存中进行操作,默认情况下,线程之间的变量修改是不可见的;当用volatile修饰变量后,一个线程执行此变量操作前会先和主存中的变量同步,同时修改后会同步刷新到主存中,保证线程之间变量修改的可见性

public class Sington {

    private volatile static  Sington instance = null;

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

③静态内部类,利用classloader的加载机制保证类初始化对象时只有一个线程,既是线程安全的,同时又没有性能损耗,日常使用时推荐

public class Sington {

    private static class LazyLoad{
        private  static  Sington INSTANCE = new Sington();
    }
    private Sington(){
    }
    public  static Sington getInstance(){
        return LazyLoad.INSTANCE;
    }
}

④枚举,在访问枚举实例的时候,会先执行构造方法,同时枚举中的属性都是static final类型的,也就表明intance只能被实例化一次,同时,枚举也提供了序列化机制,其实现了Serializable接口

public class Sington {

    private enum LazyLoad{
        INSTANCE;
        private Sington instance;
        LazyLoad(){
            instance = new Sington();
        }

    }
    private Sington(){
    }

    public  static Sington getInstance(){
        return LazyLoad.INSTANCE.instance;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值