JMM应用实例(单利模式8种写法,单例和并发的关系)

一 单例模式的作用:

节省内存和计算 保证结果正确,方便管理

二.使用场景

1.无状态的工具类:比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象即可。
2.全局信息类:比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象A上,有的却记录在对象B上,这时候我们就让这个类成为单例。

三单例模式的8种写法

1.:饿汉式(静态常量)

package singleton;

/**
 * 描述:饿汉式(静态常量)
 */
public class Singleton1 {
    //类装载时完成实例化避免线程同步问题
    private final static Singleton1 INSTANCE = new Singleton1();

    private Singleton1() {

    }

    public static Singleton1 getInstance() {
        return INSTANCE;
    }

}

2.饿汉式(静态代码块)

package singleton;

/**
 * Description: 饿汉式(静态代码块)
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 11:52
 */
public class Singleton2 {
    private final static  Singleton2 INSTANCE;
    static {
        INSTANCE = new Singleton2();
    }
    private Singleton2(){

    }
    public static Singleton2 getInstance(){
        return INSTANCE;
    }
}

  1. 懒汉式(线程不安全)(不可用)
package singleton;

/**
 * Description: 懒汉式(线程不安全)(不可用)
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 11:55
 */
public class Singleton3 {
    private static Singleton3 instance;

    private Singleton3() {

    }

    public static Singleton3 getInstance() {
        //多线程到达这一步式,有可能同时进行判断,然后创建多个实例
        if (instance == null) {
            instance = new Singleton3();
        }
        return instance;
    }
}

4懒汉式(线程安全)(不推荐)

package singleton;

/**
 * Description: 懒汉式(线程安全)(不推荐)
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 12:01
 */
public class Singleton4 {
    private static Singleton4 instance;

    private Singleton4() {

    }

    public synchronized  static Singleton4 getInstance() {
        //效率太低
        if (instance == null) {
            instance = new Singleton4();
        }
        return instance;
    }
}

5 懒汉式(线程不安全)(不推荐)

package singleton;

/**
 * Description: 懒汉式(线程不安全)(不推荐)
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 12:03
 */
public class Singleton5 {
    private static Singleton5 instance;

    private Singleton5() {

    }

    public  static Singleton5 getInstance() {

        if (instance == null) {
            //同样是线程不安全的:当两个线程同时到达这块代码的时候,虽然只能有一个线程拿到锁,
            // 然后创建实例,但创建后此线程会释放锁,另一个线程同样会再次拿到货,再次创建实例
            synchronized (Singleton5.class) {

                instance = new Singleton5();
            }
        }
        return instance;
    }
}

$6双重检查 :线程安全,延迟加载,效率较高,面试推荐

package singleton;

/**
 * Description: 双重检查 :线程安全,延迟加载,效率较高,面试推荐
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 12:06
 */
public class Singleton6 {
//volatile作用是防止重排序:实例对象是先创建一个空的对象,然后调用构造方法,最后将实例赋值到引用上,但是CPU和编译器可能进行重排序这三个顺序有可能发生颠倒,可能会使其他线程调用时,产生空指针问题
    private volatile static Singleton6 instance;

    private Singleton6() {

    }

    public static Singleton6 getInstance() {

        if (instance == null) {
            synchronized (Singleton6.class) {
                //当多个线程进入到此处时,加入双重检验,即使其他线程拿到了锁,通过判断发现已经创建了实例,所以不会再次创建.
                if (instance == null) {
                    instance = new Singleton6();
                }
            }
        }
        return instance;
    }
}

7静态内部类(线程安全和懒加载) 可用

package singleton;

/**
 * Description: 静态内部类(线程安全和懒加载) 可用
 *
 * @Auther: FengGuoXing
 * @Date: 19-10-3 12:29
 */
public class Singleton7 {

    private Singleton7() {

    }

    private static class SingletonInstance {
      private final static  Singleton7 INSTANCE = new Singleton7();
    }
    public static Singleton7 getInstance(){
        return SingletonInstance.INSTANCE;
    }


}
$8枚举单例:可用生产实践中

优点

  • 写法简单
  • 线程安全有保障
  • 避免反序列化破坏单例
package singleton;

/**
 * Description: 枚举单例:可用生产实践中
 * Joshua Bloch大神在《Effective Java》中明确表达过的观点:“使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经
 * 成为实现Singleton的最佳方法。
 * @Auther: FengGuoXing
 * @Date: 19-10-3 12:37
 */
public enum Singleton8 {
    INSTANCE;

    public void whatever() {

    }

}

四各种写法的使用场景

◆最好的方法是利用枚举,因为还可以防止反序列化重新创建新的对象;
◆非线程同步的方法不能使用;
◆如果程序-开始要加载的资源太多,那么就应该使用懒加载;
◆饿汉式如果是对象的创建需要配置文件就不适用。
◆懒加载虽然好,但是静态内部类这种方式会引入编程复杂性

你可能感兴趣的:(JMM应用实例(单利模式8种写法,单例和并发的关系))