安全发布对象

发布对象

  • 发布对象:使一个对象能够被当前范围之外的代码所使用
  • 对象溢出:一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见

不正确的发布可变对象导致的两种错误:
1.发布线程意外的所有线程都可以看到被发布对象的过期的值
2.线程看到的被发布对象的引用是最新的,然而被发布对象的状态却是过期的

  • 不安全的发布

import com.gwf.concurrency.annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;

/**
 * 不安全的发布
 * @author gaowenfeng
 * @date 2018-03-19
 */
@Slf4j
@NotThreadSafe
public class UnsafePublish {
    private String[] states = {"a","b","c"};

    /**
     * 通过public发布级别发布了类的域,在类的外部,任何线程都可以访问这个域
     * 这样是不安全的,因为我们无法检查其他线程是否会修改这个域导致了错误
      * @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()));

    }
}

  • 对象溢出

/**
 * 对象溢出
 * 在对象构造完成之前,不可以将其发布
 * @author gaowenfeng
 * @date
 */
@Slf4j
@NotThreadSafe
@NotRecommend
public class Escape {

    private int thisCannBeEscape = 0;

    public Escape(){
        new InnerClass();
    }

    /**
     * 包含了对封装实例的隐藏和引用,这样在对象没有被正确构造完成之前就会被发布,由此导致不安全的因素在里面
     * 1.导致this引用在构造期间溢出的错误,他是在构造函数构造过程中启动了一个线程,造成this引用的溢出
     *   新线程只是在对象构造完毕之前就已经看到他了,所以如果要在构造函数中创建线程,那么不要启动它,
     *   而是应该才用一个专有的start,或是其他的方式统一启动线程
     *   使用工厂方法和私有构造函数来完成对象创建和监听器的注册来避免不正确的发布
     */
    private class  InnerClass{
        public InnerClass(){
            log.info("{}",Escape.this.thisCannBeEscape);
        }
    }

    public static void main(String[] args) {
        new Escape();
    }
}

安全发布对象的四种方法

安全发布对象的四种方法

单例模式

/**
 * 懒汉模式
 * 单例的实例在第一次使用的时候进行创建
 * 双实例同步锁实现模式
 * @author gaowenfeng
 * @date
 */
@Slf4j
@ThreadSafe
public class SingletonExample6 {
    /**
     * 私有构造函数
     */
    private SingletonExample6(){
        // 可能会进行很多操作,很多运算
    }

    /**
     * 单例对象 volatile + 双重检测机制->禁止指令重排
     */
    private static volatile SingletonExample6 instance = null;

    /**
     * 静态工厂模式
     */
    public static SingletonExample6 getInstance(){
        // 双重检测机制
        if (null == instance){
            // 同步锁
            synchronized (SingletonExample6.class){
                if(null == instance){
                    instance = new SingletonExample6();
                }
            }
        }
        return instance;
    }
}
/**
 * 饿汉模式
 * 单例的实例在类加载的时候创建
 * 缺点 1.如果创建过程中进行很多的运算,会导致类加载的时候特别的慢
 *     2.如果创建出来的实例要很久以后才被调用,那么会导致资源的浪费
 * @author gaowenfeng
 * @date
 */
@Slf4j
@ThreadSafe
public class SingletonExample2 {
    /**
     * 私有构造函数
     */
    private SingletonExample2(){
        // 可能会进行很多操作,很多运算
    }

    /**
     * 单例对象
     */
    private static SingletonExample2 instance = new SingletonExample2();


    public static SingletonExample2 getInstance(){
        return instance;
    }
}
/**
 * 改造后的饿汉模式-1
 * 枚举类型的单例,最安全最简单
 * 参考:https://www.jianshu.com/p/eb30a388c5fc?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
 * @author gaowenfeng
 * @date
 */
@Slf4j
@ThreadSafe
@Recommend
public class SingletonExample8 {
    /**
     * 私有构造函数
     */
    private SingletonExample8(){
        // 可能会进行很多操作,很多运算
    }


    /**
     * 静态工厂方法
     * @return
     */
    public static SingletonExample8 getInstance(){
        return Singleton.INSTANCE.getSingletonExample8();
    }

    /**
     * 由枚举类创建单例对象
     */
    @Getter
    private  enum  Singleton{
        INSTANCE;
        
        private SingletonExample8 singletonExample8;
        Singleton(){
            singletonExample8 = new SingletonExample8();
        }

    }
}


作者:Meet相识_bfa5
链接:https://www.jianshu.com/p/c26791dbba90
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(并发学习)