首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >慕课网高并发实战(五)- 安全发布对象

慕课网高并发实战(五)- 安全发布对象

作者头像
Meet相识
发布2018-09-12 16:40:09
7530
发布2018-09-12 16:40:09
举报
文章被收录于专栏:技术专栏技术专栏技术专栏

发布对象

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

不正确的发布可变对象导致的两种错误: 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();
        }

    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.03.20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 发布对象
  • 安全发布对象的四种方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档