雷猴!我是mbb。
单例模式作为开发过程中最常用的设计模式之一,是程序员必须了解和掌握的一种设计模式,虽然单例的实现方式和手段有很多种,但每一种都有着各自的优缺点,你是否真正的了解了各自的差异?最终如何在代码中运用,就需要我们对每一种实现方式都了如指掌方可运筹帷幄。
以下介绍了Java 实现单例的全部方式、优缺点以及那些方式是推荐使用,那些是不建议使用,一起来看一下。
单例的实现方式
静态常量饿汉式
代码
代码语言:javascript复制public class Single {
private static Single single = new Single();
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
public static Single getInstance() {
return single;
}
}
优点
- 线程安全;
- 没有锁存在,执行性能高;
缺点
- 没有实现懒加载,可能产生垃圾对象(即使不用,也会实例化),如果能确定这个对象必定会使用,可以考虑这种方式
静态代码块饿汉式
代码
代码语言:javascript复制public class Single {
private static Single single = null;
static{
single = new Single();
}
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
public static Single getInstance() {
return single;
}
}
优点
- 线程安全;
- 没有锁存在,执行性能高
缺点
- 没有实现懒加载,可能产生垃圾对象,如果能确定这个对象必定会使用,可以考虑这种方式
懒汉式一(不要使用)
代码
代码语言:javascript复制public class Single {
private static Single single = null;
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
private static Single getInstance() {
// 当多个线程同时执行带这里的时候,会创建出多个对象
if (null == single) {
single = new Single();
}
return single;
}
}
优点
- 实现了懒加载;
缺点
- 非线程安全,无法保证单例,所以,不要使用。
懒汉式二(不推荐使用)
代码
代码语言:javascript复制public class Single {
private static Single single = null;
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
private static synchronized Single getInstance() {
if (null == single) {
single = new Single();
}
return single;
}
}
优点
- 实现了懒加载;
- 实现起来容易,代码容易理解;
缺点
- 锁粒度太粗,导致执行的性能会下降
懒汉式三(不要使用)
代码
代码语言:javascript复制public class Single {
private static Single single = null;
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
private static Single getInstance() {
if (null == single) {
// 当多个线程通知执行到这里来了之后,无法保证对象单一
synchronized(Single.class){
single = new Single();
}
}
return single;
}
}
优点
- 实现了懒加载;
缺点
- 线程不安全,无法保证对象单一,所以,不要使用。
双重检查DCL(推荐使用)
代码
代码语言:javascript复制public class Single {
//这里一定要加volatile 否则可能因为指令重排的问题导致对象未初始化完成的情况
private volatile static Single single = null;
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
public static Single getInstance() {
if (null == single) {
synchronized (Single.class) {
if (null == single) {
single4 = new Single();
}
}
}
return single;
}
}
优点
- 实现了懒加载;
- 锁粒度较细,只有第一次初始化的时候会走到synchronized部分
缺点
- 实现起来相对复杂,对于volatile的理解会比较的难
静态内部类(推荐使用)
代码(内部类的方式)
代码语言:javascript复制public class Single {
// 一定要将默认构造方法设置为private 否则反射实例化将破坏单例
private Single() {
}
private static class LazyHolder {
private static final Single INSTANCE = new Single();
}
public static Single getInstance() {
return LazyHolder.INSTANCE;
}
}
优点
- 实现了懒加载;
- 没有锁,性能较好
缺点
- 实现及理解起来相对复杂
枚举单例(推荐使用)
代码
代码语言:javascript复制public enum Single6
{
INSTANCE;
public void test()
{
System.out.println("test()");
}
}
优点
- 线程安全;
- 实现简单,理解容易;
缺点
- 未实现了懒加载;
总结
以上列举了开发过程中所有的单例实现方式,同时还列出了详细的其详细的优缺点;对于枚举方式、DCL方式以及静态内部类的方式是个人相对比较推荐的方式;可以视情况使用;至于饿汉式的两种写法,由于比较简单,如果对应的单例对象在系统中必定用到而且频繁使用,也可以考虑使用;所以,没有更好,只有最好!合适才好!!!