LazySingleton 将对象的初始化推迟到调用的时候。并且为了防止多线程环境下产生多个实例,使用synchronized关键字保证函数getInstance调用的线程 安全。synchronized关键字的存在保证了只会产生一个对象,但也成了多线程环境下的性能瓶颈。一个多线程的程序,到了这里却要排队等候成了一个 单线程式的执行流程,这在高并发环境下是不可容忍的。而c++中可以使用双重检查机制将这种性能问题仅仅限制在第一次构造对象的时候,而java中不可以 使用双重检查机制。
但是java可以实现EagerSingleton,实现如下:
该类含有一私有属性value,在多线程环境下不能保证value值的合理逻辑,一线程getValueByName后,马上printValue,也有可能value的值已经被其他线程修改。这种情况就属于单例模式的滥用,该类根本不适合做成单例。
消除非法逻辑的陷阱,可以通过将该类重构为纯粹的行为类完成。重构后的代码如下:
通过调用printName(String name)直接完成操作流程,将其中的私有属性处理成过程式的参数传递,将该类修改成纯粹的行为类。
含有私有属性并且含有对它赋值操作的类并非都会调入该陷阱,构造函数里进行对私有属性赋值不会引起非法逻辑,如下代码
构造函数里不必要加线程安全关键字也可以保证线程安全,因为类加载器是线程安全的,EagerSingleton只会在类加载的时候实例化一次,这样不会出现单例模式的线程不安全,也不会造成非法逻辑。
(4)陷阱四:单例陷阱的传递
当含有对象作为单例类的私有属性时,陷阱不仅会出现在该类本身,还会传递到私有对象所在的类中。看如下代码: