java并发编程实战wwj----------------------第二阶段--------------01-02-03

架构设计。

--------------------------------------01-----------------------------------------------------

代码:

单例的恶汉模式:

public class SinglenObject1 {
    private static final SinglenObject1 instance  = new SinglenObject1();
    private SinglenObject1(){

    }
    public static SinglenObject1 getInstance(){
        return instance;
    }
    public static void main(String[] args) {

    }
}

static用这个类就已经加载了,出现的问题就是我很长时间不使用的话就会一直存在的。

单例的懒汉模式非线程安全:

package two.chapter1;

public class SinglenObject2 {
    private static SinglenObject2 instance;
    private SinglenObject2(){
        //empty
    }
    public static SinglenObject2 getInstance(){
        if(null==instance){//这里会出现线程安全问题
            instance = new SinglenObject2();
        }
        return SinglenObject2.instance;
    }

}

单例的懒汉模式,线程安全:

方案1:加在这里会影响性能

双重校验锁:

优化到读不加锁。

public class SinglenObject3 {
    private static SinglenObject3 instance;
    private SinglenObject3(){
        //empty
    }
    public static SinglenObject3 getInstance(){
        if(null==instance){
            synchronized (SinglenObject3.class){
                if(null==instance){
                    instance = new SinglenObject3();
                }
            }
        }
        return instance;
    }
}

----------------------------------------02-------------------------------------

遗留的问题:可能会引起空指针异常

假设一个哥们抢到了锁new了单例,会在堆开辟空间的。   

但是此时里面的属性如构造函数并没有构造完毕。另一个哥们就拿去用了,就会空指针异常。

如何解决这个问题?

加volatile保证可见性。严格遵循happendsbefore。

volatile读的时候必须保证写全部完成。

public class SinglenObject4 {
    private static volatile SinglenObject4 instance;
    private SinglenObject4(){
        //empty
    }
    public static SinglenObject4 getInstance(){
        if(null==instance){
            synchronized (SinglenObject4.class){
                if(null==instance){
                    instance = new SinglenObject4();
                }
            }
        }
        return instance;
    }
}

一种优雅的方式---强烈建议的,就是内部类恶汉作者推荐:

public class SinglenObject5 {
    private SinglenObject5() {

    }
    private static class InstanceHolder {
        private final static SinglenObject5 instance = new SinglenObject5();
    }
    public static SinglenObject5 getInstance() {
        return InstanceHolder.instance;
    }
}

static使用才会被加载,不使用不会被加载。

static只会初始化一次的,只有一个的。

枚举是线程安全的,构造函数只会装载一次。

枚举的方式:

public class SinglenObject6 {
    private SinglenObject6() {
        //empty
    }
    private enum Singleton{//枚举事线程安全的而且构造函数只会被装载一次的
        INSTANCE;
        private final SinglenObject6 instance;
        Singleton(){
            instance = new SinglenObject6();
        }
        public SinglenObject6 getInstance(){
            return instance;
        }
    }

    public static SinglenObject6 getInstance(){
        return Singleton.INSTANCE.getInstance();
    }

    public static void main(String[] args) {
        IntStream.rangeClosed(1,100).forEach(i->new Thread(String.valueOf(i)){
            @Override
            public void run(){
               System.out.println(SinglenObject6.getInstance());
            }
        }.start());
    }
}

枚举的构造函数是私有的只会被装载一次。枚举类私有。

定义INSTANCD的时候,构造函数就已经创建了。

-----------------------------------03-------------------------------------

问题的补充:单例为什么加volatile:https://www.cnblogs.com/tiancai/p/9927948.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值