单例模式的懒汉模式与饿汉模式的区别在于单例的生成时间,在系统启动时就生成的是饿汉模式,在运行时生成的是懒汉模式。懒汉模式存在一个问题,在多线程的环境下,锁里要加判空逻辑,需要加上双重if判断逻辑以保证程序效率,不能将整个初始化方法全部加锁。
懒汉模式在运行时生成需要的单例对象。先考虑单线程的情况。在单线程的情况下,第一次访问这个单例,由于是懒加载,所以并没有真正的实例,需要初始化一个实例对象出来,并将其返回。后面再次访问这个单例,由于第一次已经初始化过了,所以会直接返回已经生成的实例对象。
在多线程的环境下,会出现多个线程同时访问单例的情况。这里需要分两种情况讨论。当单例中已经存在实例对象的时候,此时同时返回即可。当单例中不存在实例对象的时候,也就是多线程第一次同时访问该单例的时候,就会出现多个对象同时创建实例对象的情况。
同时创建实例对象情况可能对系统一致性有影响,也可能只是增加了一些冗余操作。无论是哪一种我们都应该避免。
如何保证一个单例对象在多线程环境下只执行一次初始化实例的动作?需要加锁。不同的加锁方式会有不同的性能开销,因此需要探索最佳实践。
最简单的方式在单例模式上整个加锁,同一时刻只有一个线程访问该单例。这样可以保证实例对象只创建一次,但是多线程在获取单例的时候是串行,效率极其低下。
考虑是否可以缩小锁的范围。只在需要初始化实例的地方加锁。这样的逻辑就变成,访问单例时,第一步判断是否需要初始化实例对象,不需要的话立刻返回,如果需要则加互斥锁,第一个拿到互斥锁的初始化实例对象并返回,被锁阻塞住的对象一一进入创建锁的流程中,此处第二判断实例对象是否需要初始化,不是第一个拿到互斥锁的对象在这一次判断中直接返回实例对象,不需要初始化。
优化单例里的懒汉模式并发性能
最新推荐文章于 2024-08-24 11:46:12 发布