单例模式理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cyn_653620/article/details/82497529

单例模式在开发过程中

遇到的几个场景:
       1、网站计数器,一般是采用单例模式实现,否则难以同步。
       2、由于配置文件一般都是共享资源,即web应用的配置对象的读取,一般采用单例模式来实现。如:spring的配置文件的读取等
       3、多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
       4、数据库连接池的设计也是采用单例模式的。数据库连接其实也是一种数据连接的共享资源,在jdbc连接中如果在做频繁操作的时候,不停的打开或者关闭会效能损耗,因此用单例模式来维护就大大降低了这种效能损耗。

       其实,通过介绍单例模式出现的目的,操作系统中的应用实例和开发中遇到的几个场景,我们应该大概知道了什么时候应该使用单例模式进行开发了。所以单例模式应用的场景一般有两个条件:
       1、资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的应用配置、数据连接池的设计。
       2、控制资源的情况下,方便资源之间的互相通信。如多线程的线程池设计等。

      所以,单例模式的适应场景如:
      1、需要频繁实例化然后销毁的对象。
      2、创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
      3、有状态的工具类对象。
      4、频繁访问数据库或文件的对象

单例模式包含(懒汉式和饿汉式)

使用场景区别:
 如果单件模式实例在系统中经常会被用到,饿汉式是一个不错的选择。
 反之如果单件模式在系统中会很少用到或者几乎不会用到,那么懒汉式是一个不错的选择。

单例模式(懒汉式)

懒汉式 当程序第一次访问单件模式实例时才进行创建。

在懒汉式写法中, 我们需要非常注意线程同步的问题. 大概有一下几个: 
1. getInstance() 直接锁方法好不好 
2. 双重锁定 
3. synchronized(this)行不行

1. getInstance() 直接锁方法好不好

这种写法:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

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

我们可以看到这里synchronized是锁方法, 当两个线程都要进入getInstance()时, 只有一个能进入, 并创建出实例, 然后另外一个进入后, 判断 instace不为null, 然后直接得到instance. 这种做法是没有错误的. 但是由于线程都需要通过getInstance()来获取对象, 所以getInstance()调用频率很高, 所以线程被锁的频率也很高, 所以这种做法效率低.

2. 双重锁定

由于上面效率的原因, 你可能就会想到把 syschronized 放在 getInstance()里面, 这种可避免在调用getInstance()时的阻塞问题, 如下:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

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

这种写法看似没有问题, 其实却有一个很大的隐患, 在于: 如果两个线程同时执行getInstance(),判断 instance都不为null后, 进入if判断语句. 这个时候一个线程获得锁, 然后进入new了一个对象, 并开心的执行完了. 这个时候另外一个线程获得了锁, 但让它也不会再去判断 instace是否为null, 所以它也会再执行一次new操作. 所以这里执行了两次new操作. 当然最后instance还是只指向后一次new的对象. 
所以这个时候需要双重锁定, 就是在 synchronized中再加一次 null判断, 如下:

//懒汉式-双重检验锁-线程安全
class Singleton3 {
	private static  Singleton3 singleton;
	
	private Singleton3(){}
	
	public static Singleton3 getInstance(){
		if(singleton==null){// 第一步检验锁
			synchronized (Singleton3.class) {
				if(singleton==null){// 第二步检验锁
					singleton = new Singleton3();
				}
			}
		}
		return singleton;
	}
	  
}

这样就可以保证不会new两次, 也是相对比较正确的, 并且效率也很高.

3. synchronized(this)行不行

答案是不行的, 如果你写代码看一看, 直接就提示语法错误了, 因为我们的 getInstance() 方法是 static的, 所以里面不能使用 this.

单例模式(饿汉式)

饿汉式 在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。

代码如下:

//饿汉式
class Singleton1 {
	private static  Singleton1 singleton= new Singleton1();
	
	private Singleton1(){}
	
	public static Singleton1 getInstance(){
		return singleton;
	}
	  
}

单例锁理解:https://www.cnblogs.com/huansky/p/8869888.html

猜你喜欢

转载自blog.csdn.net/cyn_653620/article/details/82497529