应用场景
只需要一个实例
- 如各种Mgr (manager管理类)
- 如各种Factory
饿汉式
- 类加载到内存后,就实例化一个单例,JVM保证线程安全
- 简单实用,推荐使用
- 缺点:不管是否用到,类装载时就完成实例化
/**
*饿汉式:
*
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 简单实用,推荐使用
* 缺点:不管是否用到,类装载时就完成实例化
*/
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
// 构造方法私有化
private Mgr01() {};
// 暴露给外部调用,返回同一个对象,保证单例
public static Mgr01 getInstance() {
return INSTANCE;
}
// 其它方法
public void m(){};
}
懒汉式
写法1
优点:按需初始化
缺点:多线程时可能会创建多个实例
/**
* lazy loading
* 也称懒汉式
* 虽然达到了按需初始化的目的,但多线程时会有一些问题
*/
public class Mgr02 {
private static Mgr02 INSTANCE;
// 构造方法私有化
private Mgr02() {};
// 该方法被调用时才创建实例
public static Mgr02 getInstance() {
// 此时若正好有多个线程进入判断,那么会new出多个对象
if ( INSTANCE == null) {
INSTANCE = new Mgr02();
}
return INSTANCE;
}
// 其它方法
public void m(){};
}
写法2
- 加锁改进后解决多线程问题,但效率降低
/**
* 懒汉式改进
*
* 可以通过synchronized解决多线程问题,但也带来效率下降
*/
public class Mgr03 {
private static volatile Mgr03 INSTANCE;
// 构造方法私有化
private Mgr03() {};
// 加锁
public static synchronized Mgr03 getInstance() {
if ( INSTANCE == null) {
INSTANCE = new Mgr03();
}
return INSTANCE;
}
// 其它方法
public void m(){};
}
写法3
- 若想再进一步提高效率:判空后再加锁,双重检查锁(double-checked locking)
public class Mgr04 {
private static volatile Mgr04 INSTANCE;
// 构造方法私有化
private Mgr04() {};
// 该方法被调用时才创建实例
public static Mgr04 getInstance() {
if ( INSTANCE == null) {
// 双重检查 如果是单次检查,仍有可能有多个线程进入if判断
synchronized (Mgr04.class) {
if ( INSTANCE == null ) {
INSTANCE = new Mgr04();
}
}
}
return INSTANCE;
}
// 其它方法
public void m(){};
}
写法4
- 静态内部类方式。懒加载,JVM保证线程安全。
Mgr05类被加载时,内部类Mgr05Holder不会被加载,当getInstance()方法被调用时Mgr05Holder才会被加载,从而实现了懒加载
/**
* 静态内部类方式
* JVM保证单例
* 加载外部类时不会加载内部类,这样可以实现懒加载
*/
public class Mgr05 {
// 构造方法私有化
private Mgr05() {};
// 静态内部类
private static class Mgr05Holder {
private static final Mgr05 INSTANCE = new Mgr05();
}
public static Mgr05 getInstance() {
return Mgr05Holder.INSTANCE;
}
// 其它方法
public void m(){};
}
写法5
- 枚举单例,语法上最完美
/**
* 不仅可以解决线程同步,还可以防止反序列化
*/
public enum Mgr06 {
INSTANCE;
// 其它方法
public void m(){};
}
网友评论