java 并发编程学习笔记(四)之 安全发布对象(单例模式实现几种实现方式)

                                          安全发布对象

错误发布对象:

发布对象:使一个对象能被当前范围之外的代码所使用

对象溢出:一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见

如何 安全 发布对象呢 ?一般采用 以下四种方式

java 并发编程学习笔记(四)之 安全发布对象(单例模式实现几种实现方式)_第1张图片

(1)首先来看一个 非安全发布对象代码:

@Slf4j
public class UnSafePublish {

    private String[] states = {"a", "b", "c"};

    /**
     * 无法确保 其他的线程会通过调用此方法,来修改私有的成员变量
     *
     * @return
     */
    public String[] getStates() {
        return states;

    }

    public static void main(String[] args) {
        UnSafePublish unSafePublish = new UnSafePublish();
        log.info("{}", Arrays.toString(unSafePublish.getStates()));

        unSafePublish.getStates()[0] = "d";
        log.info("{}", Arrays.toString(unSafePublish.getStates()));
    }
}

(2)非安全的 对象溢出

public class Escape {

    private  int thisCanBeEscape =0 ;
    /**一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见*/
    public Escape() {
         new InnerClass();
    }

    private class  InnerClass{
        public  InnerClass(){
            log.warn("{}",Escape.this.thisCanBeEscape);
        }
    }
    public static void  main(String[] args){
        new Escape();
    }
}

 (3)单例模式的 几种方式比较

  • 懒汉模式
/**
 * 懒汉模式
 * 单例的实例在第一次使用的时候进行创建
 * 

* 在单线程的环境下,没有问题,但是在多线程的环境下就会出问题。 */ @NotThreadSafe @Slf4j public class SingletonExample1 { //私有构造函数 private SingletonExample1() { } //单例对象 private static SingletonExample1 instance = null; //静态的工厂方法 //懒汉模式本身时线程不安全的,加上了synchronized关键字之后就可以实现安全 //但是降低了性能,因此并不推荐这种写法 public static synchronized SingletonExample1 getInstance() { if (instance == null) { instance = new SingletonExample1(); } return instance; } }

  • 饿汉模式 
/**
 * 饿汉模式
 */
public class SingletonExample2 {


    private SingletonExample2() {

    }

    private static SingletonExample2 singletonExample2 = new SingletonExample2();

    public static SingletonExample2 getInstance() {
        return singletonExample2;
    }
}
  •  懒汉模式+ 双重检测同步锁
/**
 * 懒汉模式 -》》双重同步锁单例模式
 */
@NotThreadSafe
@Slf4j
public class SingletonExample3 {
    //私有构造函数
    private SingletonExample3() {

    }
    /**
     * 1.分配对象的内存空间
     * 2.初始化对象
     * 3.设置instance 指向刚分配的内存
     * 在单线程的情况下没有问题,但是在多线程的情况下
     *
     * jvm 和cpu 优化,发生指令重排
     *
     * 1.分配对象的内存空间
     * 2.设置instance 指向刚分配的内存
     * 3.初始化对象
     *
     * 因此我们需要限制SingletonExample3类的创建的时候的指令重排,添加volatile关键字
     */


    //单例对象
    //volatile 加上 双重检测机制,禁止指令重排
    private volatile static SingletonExample3 instance = null;


    //静态的工厂方法
    public static  SingletonExample3 getInstance() {
        if (instance == null) {     //双重检测机制
             synchronized (SingletonExample3.class) { //同步锁
                 if (instance == null) {
                     instance = new SingletonExample3();
                 }
             }
        }
        return instance;
    }
}
  •  饿汉模式 (静态块的方式)
/**
 * static 静态块的饿汉模式
 */
public class SingletonExample6 {
    private  SingletonExample6(){}

    private static SingletonExample6 instance =null;

    static  {
        instance = new SingletonExample6();
    }

    private  static  SingletonExample6 getInstance(){
        return instance;
    }
    
    public static void  main(String[] args){
        System.out.println(getInstance());
        System.out.println(getInstance());
    }
}
  • 枚举模式(最推荐) 
/**
 * 枚举模式,最安全
 * 利用枚举的特性,一个枚举的构造方法只会被调用一次实现单例模式,推荐使用这种方式
 * 

* 优点:1、相比懒汉模式,更能保证线程安全性 * 2、相比饿汉模式,也只会在第一次使用的时候进行创建实例,不会造成资源浪费 */ @ThreadSafe @Recommend public class SingletonExample7 { private SingletonExample7() { } public static SingletonExample7 getInstance() { return Singleton.INSTANCE.getInstance(); } private enum Singleton { INSTANCE; //只有一个枚举变量,保证构造方法只调用一次 private SingletonExample7 singletonExample7; //jvm保证这个方法绝对只调用一次 Singleton() { System.out.println("我只会被调用一次"); singletonExample7 = new SingletonExample7(); } public SingletonExample7 getInstance() { return singletonExample7; } } public static void main(String[] args) { System.out.println(SingletonExample7.getInstance()); System.out.println(SingletonExample7.getInstance()); System.out.println(SingletonExample7.getInstance()); } }

 

你可能感兴趣的:(java,多线程)