我知道Java中的双重锁定已损坏,因此使Java中的Singletons线程安全的最佳方法是什么?我想到的第一件事是:
class Singleton{ private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance == null) instance = new Singleton(); return instance; } }
这样行吗?如果是这样,那是否是最好的方法(我想这取决于具体情况,因此说明何时使用特定技术是最好的方法)
Josh Bloch建议使用单元素enum类型实现单例(请参阅 有效的Java 2nd Edition,第3项:使用私有构造函数或枚举类型强制单例属性 )。
enum
有人认为这是黑客,因为它并未明确传达意图,但确实有效。
以下示例直接取自本书。
public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } }
这是他的结束语:
此方法更加简洁,免费提供了序列化机制,甚至面对复杂的序列化或反射攻击,也提供了针对多个实例的明确保证。尽管此方法尚未得到广泛采用, 但是单元素枚举类型是实现单例的最佳方法 。
8.9。枚举](http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9)
枚举类型除了由其枚举常量定义的实例外,没有其他实例。尝试显式实例化枚举类型(第15.9.1节)是一个编译时错误。 中的final clone方法Enum确保永远不会克隆枚举常量,并且序列化机制的特殊处理确保了绝不会由于反序列化而创建重复的实例。禁止枚举类型的反射实例化。总之,这四件事确保了枚举类型的实例不存在超出枚举常量定义的实例的情况。
枚举类型除了由其枚举常量定义的实例外,没有其他实例。尝试显式实例化枚举类型(第15.9.1节)是一个编译时错误。
中的final clone方法Enum确保永远不会克隆枚举常量,并且序列化机制的特殊处理确保了绝不会由于反序列化而创建重复的实例。禁止枚举类型的反射实例化。总之,这四件事确保了枚举类型的实例不存在超出枚举常量定义的实例的情况。
final clone
Enum
以下代码段:
public class LazyElvis { enum Elvis { THE_ONE; Elvis() { System.out.println("I'M STILL ALIVE!!!"); } } public static void main(String[] args) { System.out.println("La-dee-daaa..."); System.out.println(Elvis.THE_ONE); } }
产生以下输出:
La-dee-daaa... I'M STILL ALIVE!!! THE_ONE
如您所见,THE_ONE在第一次访问常量之前,不会通过构造函数实例化常量。
THE_ONE