线程安全-安全发布对象

安全发布对象

发布与溢出

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

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

发布代码演示

public class PublishExample1 {
    private String[] status={"a","b","c"};

    public String[] getStatus(){
        return status;
    }

    public static void main(String[] args) {
        PublishExample1 example1=new PublishExample1();
        System.out.println(Arrays.toString(example1.getStatus()));
        example1.getStatus()[0]="d";
        System.out.println(Arrays.toString(example1.getStatus()));
    }
}

注:通过代码的访问级别发布了外部的域,在类的任何外部的线程都可以访问这些域,这样的发布对象其实是不安全的,无法保证其它线程会不会修改这些域

溢出代码演示

public class PublishExample2 {
    private int count=0;

    public PublishExample2(){
        new Inner();
    }

    private class Inner{
        public Inner(){
            System.out.println("count:"+PublishExample2.this.count);
        }
    }

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

注:在对象没有正确构造完成之前就被发布,容易造成一些不安全因素,这里可以采用工厂方法、私有构造函数来完成对象创建和构造器的注册,这里的目的是对象未完成注册之前不可以发布对象

安全发布对象—四种方法

在静态初始化函数中初始化一个函数的引用,非线程安全

/**
 * 懒汉模式
 * 第一次加载时初始化
 */
public class SingletonExample1 {

    private SingletonExample1(){}

    private static SingletonExample1 example1=null;

    public static SingletonExample1 getInstance(){
        if(example1==null){
            example1=new SingletonExample1();
        }
        return example1;
    }
}

注:非线程安全

/**
 * 饿汉模式
 * 类装载使用时被创建
 */
public class SingletonExample2 {

    private SingletonExample2(){}

    private static SingletonExample2 example1=new SingletonExample2();

    public static SingletonExample2 getInstance(){
        return example1;
    }
}

注:如果构造方法中存在过多的处理,会造成类加载的时候特别的慢,引起性能问题,如果使用饿汉模式只使用类的加载没有实质使用会造成资源浪费

/**
 * 饿汉模式--静态快
 * 类装载使用时被创建
 */
public class SingletonExample6 {

    private SingletonExample6(){}
    private static SingletonExample6 example1=null;

    static {
        example1=new SingletonExample6();
    }


    public static SingletonExample6 getInstance(){
        return example1;
    }

    public static void main(String[] args) {
        System.out.println(getInstance().hashCode());
        System.out.println(getInstance().hashCode());
    }
}

注:静态块中初始化,注意example1定义和static块的位置,private static SingletonExample6 example1=null;放在static下方会报空指针

/**
 * 枚举实现单例模式---线程安全,推荐使用
 * 类装载使用时被创建
 */
public class SingletonExample7 {

    private SingletonExample7(){}



    public static SingletonExample7 getInstance(){
        return Singleton.INTEGEN.getInstance();
    }

    private enum Singleton{
        INTEGEN;
        private SingletonExample7 example7=null;

        private Singleton(){
            example7=new SingletonExample7();
        }

        
        public SingletonExample7 getInstance(){
            return example7;
        }
    }

    public static void main(String[] args) {
        System.out.println(getInstance().hashCode());
        System.out.println(getInstance().hashCode());
    }
}

注:绝对安全,枚举中构造方法时JVM保证该方法绝对只被执行一次,推荐这种方式

将对象的引用保存到volatile类型或着AtomicReference对象中

/**
 * 懒汉模式---双重校验锁,使用volatile优化
 * 第一次加载时初始化
 */
public class SingletonExample5 {

    private SingletonExample5(){}

    private static volatile SingletonExample5 example1=null;

    public static SingletonExample5 getInstance(){
        if(example1==null){
            synchronized (SingletonExample5.class){//同步锁
                if(example1==null){//双重检测
                    example1=new SingletonExample5();
                }
            }
        }
        return example1;
    }
}

注:优化双重校验锁,线程安全

将对象的引用保存到某个正确构造对象的final类型域中

将对象的引用保存到一个由锁保护的域中

/**
 * 懒汉模式
 * 第一次加载时初始化
 */
public class SingletonExample1 {

    private SingletonExample1(){}

    private static SingletonExample1 example1=null;

    public static  synchronized SingletonExample1 getInstance(){
        if(example1==null){
            example1=new SingletonExample1();
        }
        return example1;
    }
}

注:线程安全但不推荐使用,被synchronize修饰,同一时刻只允许一个线程访问,影响性能

/**
 * 懒汉模式---双重校验锁
 * 第一次加载时初始化
 */
public class SingletonExample4 {

    private SingletonExample4(){}

    private static SingletonExample4 example1=null;

    public static  SingletonExample4 getInstance(){
        if(example1==null){
            synchronized (SingletonExample4.class){//同步锁
                if(example1==null){//双重检测
                    example1=new SingletonExample4();
                }
            }
        }
        return example1;
    }
}

注:双重检验锁单例模式,但是并非线程安全的,当一个线程访问后发现synchronize进行实例化后,第二个线程在访问发现已经实例化,就不会往下继续执行这些都没有问题,问题出在,分三个步骤,1、分配对象内存空间,2、初始化对象。3、设置指向刚分配的内存,在多线程环境下会指令重排,如JVM和cpu优化发生了指令重排,上面的3个步骤发生了顺序上的变化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值