Java多线程之实现单例模式

什么是单例模式

  • 首先我们先了解一下什么是单例模式,其实单例模式是创建类型的一种常用的软件设计模式,也是我们多线程编程中用的最多,最重要的一种设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)
  • 其实最简单的理解就是顾名思义,单例模式就是只有一个实例化对象。

单例模式的实现方式

  • 饿汉模式

     饿汉模式就是再类加载的时候就把对象创建好,不管用不用都会被创建
    
class Test{    //单例模式之饿汉模式
   		private static Test t = new Test();
        private Test() {}     //把构造方法私有化,禁止类外部
        private static Test getTest(){
            return t;
        }
}
  • 懒汉模式

      懒汉模式就是什么时候调用,什么时候创建,相比于饿汉模式效率比较高,不会浪费空间内存
    
 class Test2{    //单例模式之懒汉汉模式
        private static Test2 t = null;
        private Test2() {}
        private static Test2 getTest(){
            if(t == null) {
                t = new Test2();  //只有第一次调用getTest才会new一个新对象,之后再调用就会直接返回第一次创建好的。
            }                    
            return t;
        }
    }

-双检模式

public class Singleton {
    public static volatile Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        //采用两个if可以解决第二次调用的时候会触发获取锁的操作;
        if (instance == null) {
            synchronized (Singleton.class) {
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 我们之前已经了解过饿汉模式和懒汉模式了,那我们的双检模式和前两个模式的区别就在于多了一个synchornized代码块,然后多了两个 if 判断语句,多了个volatile关键字
synchornized代码块

首先我们说为什么要用synchornized锁,当有两个线程同时执行了getIntance方pan创建对象的时

候,这个时候intance是null,然后两个线程就会同时new出来两个新对象,然后返回,这就失去了我们

单例模式的意义。当我们加上锁之后,当第一个线程正在执行获取到锁的时候,线程2就会等待,等线

程1结束的时候,线程2就会获取到锁,然后判断intance不为空,就会返回线程1已经创建好的对象,**

这就保证了多线程并发执行getInstace方法的时候,仍然能保证是单例模式**;

双if语句(双检)

然后我们说为什么要用两个 if 语句,synchornized锁里面 if 语句我们已经知道作用了,防止重复创建

实例化对象。如果我们不用synchornized外面的 if ,那么程序每次都会获取锁,释放锁,然后再判断

instance是否为空,程序每次释放锁,获取锁也是会很耗费系统的资源,影响程序的效率,再加一个 if

的话,当instance不为空,也不用获取锁,会直接返回之前创建好的。**这样做能避免程序进行无意义

的获取释放锁**,极高的提高程序的执行效率。

volatile关键字

我们之所以在单例模式中使用volatile,是为了解决jvm指令重排序带来的问题。并不是为了解决内存可见性问题,synchornized已

经为我们解决了内存可见性问题。

例如 instance = new Singleton();这个操作就不是原子性的,它的执行过程如下:

  1. 给instance分配内存
  2. 调用Singleton的构造函数进行初始化
  3. 将instance对象指向分配的内存空间

经过我们JVM优化之后,顺序就可能变成1,3,2,即先将instance指向未初始化完成的内存空间,只有执行完第三步之后,

instance才不为空

如此此时线程A先将instance指向未初始化完成的内存空间,然后线程B执行getInstance方法,获取到instance不为空返回,此时

获取到的instance就是未初始化完成的,调用的时候就会出错。

单例模式的作用

我们实现单例模式的目的是为了什么,为了让程序中只有一个实例化对象(比如某个大型服务器中存了大量的数据,我们的服务

器程序不想让系统中存在太多这样重复的大对象),之所以设计这种模式,是因为如果我们手动控制让一个类只被new一次,不

被重复new,要靠程序员手工去实现,但是这样是不太靠谱的。而我们实现了单例模式后,单例模式就可以让编辑器自动帮我们

做更充分的检查,类似于编辑器会自动检查final,abstract关键字一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值