单例模式及变种代码实现

        最近快过年了,也没心思弄其他的,就把一些乱七八糟的总结总结写下吧,今天讲讲单例模式的几种写法,例如懒汉式、饿汉式,以及相关变种,有问题的请及时沟通。

        何为单例模式?所谓单例模式,简单来说就是实例只能有一份的类。因此单例的核心就是构造器私有,这样外部类才不能通过new来创建这个类,只能调用这个类给外部的方法来创建一份实例。

1.饿汉式

public class SingleTon {

    private SingleTon(){

    }

    private static final SingleTon SINGLETON = new SingleTon();

    public static SingleTon getInstance(){
        return SINGLETON;
    }
}

优点:类装载的时候就实例化该类,避免了线程同步的问题

缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

2.饿汉式变种

public class SingleTon {

    private static SingleTon singleTon;

    static {
        singleTon = new SingleTon();
    }

    private SingleTon(){

    }

    public static SingleTon getInstance(){
        return singleTon;
    }
}

这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。

3.懒汉式

public class SingleTon {

    private static SingleTon singleTon;

    private SingleTon(){

    }

    public static SingleTon getInstance(){
        if(singleTon == null){
            singleTon = new SingleTon();
        }
        return singleTon;
    }
}

优点:达到Lazy Loading的效果

缺点:只能在单线程中使用,多线程的情况下并发会产生多个实例

4.懒汉式变种(1)

public class SingleTon {

    private static SingleTon singleTon;

    private SingleTon(){

    }

    public static synchronized SingleTon getInstance(){
        if(singleTon == null){
            singleTon = new SingleTon();
        }
        return singleTon;
    }
}

优点:达到Lazy Loading的效果,多线程情况下线程安全

缺点:把整个方法块都加锁了,所有进入这个方法的线程都得等待,效率低

5.懒汉式变种(2)

public class SingleTon {

    private static SingleTon singleTon;

    private SingleTon(){

    }

    public static SingleTon getInstance(){
        if(singleTon == null){
            synchronized (SingleTon.class){
                singleTon = new SingleTon();
            }
        }
        return singleTon;
    }
}

优点:达到Lazy Loading的效果

缺点:线程不安全,虽然第4种将整个方法进行同步了,但是由于效率太低,就把初始化类给同步,但是还是会出现线程不安全的问题,当多个线程同时进入if(singleTon == null),都会继续往下走

6.懒汉式变种(3):双重检查

public class SingleTon {

    private static volatile SingleTon singleTon;

    private SingleTon(){

    }

    public static SingleTon getInstance(){
        if(singleTon == null){
            synchronized (SingleTon.class){
                if(singleTon == null){
                    singleTon = new SingleTon();
                }
            }
        }
        return singleTon;
    }
}

优点:达到Lazy Loading的效果;线程安全;

注意:细心的同学能看到定义的singleTon被定义为volatile的,volatile简单来说就是提醒编译器实时注意定义变量的变化,不然双重检查时singleTon还是没变化,检查了就没用了。

7.懒汉式变种(4):静态内部类

public class SingleTon {

    private SingleTon(){

    }

    private static class innerSingle{
        private static final SingleTon SINGLETON = new SingleTon();

    }

    public static SingleTon getInstance(){
        return innerSingle.SINGLETON;
    }
}

优点:避免了线程不安全,延迟加载,效率高。

这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

适用场景:

(1)需要频繁的进行创建和销毁的对象;

(2)创建对象时耗时过多或耗费资源过多,但又经常用到的对象;

(3)工具类对象;

(4)频繁访问数据库或文件的对象。

以下都是单例模式的经典使用场景: 

(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。 
(2)控制资源的情况下,方便资源之间的互相通信。如线程池、数据库连接池等。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值