设计模式-单例模式

单例模式(Singleton)

单例模式之饿汉式
//饿汉式,类加载到内存后,就实例化一个单例,JVM保证线程安//全,简单实用,推荐使用
//缺点:不管用到与否,类装载时就完成实例化
public class Mgr01 {
//
    private static final Mgr01 INSTANCE = new Mgr01();

    private Mgr01() {

    }

    public static Mgr01 getInstance() {
        return INSTANCE;
    }

    public static void main(String[] args) {
        Mgr01 m1 = Mgr01.getInstance();
        Mgr01 m2 = Mgr01.getInstance();
        System.out.println(m1 == m2);
    }
}

单例模式之懒汉式
//也称懒汉式
//虽然达到了按需初始化的目的,但是确带来了线程不安全的风险
public class Mgr03 {

    private static Mgr03 INSTANCE;
	//注意此处的构造方法是私有方法,所以该类不能在其他类中通过构造函数进行实例化
    private Mgr03() {

    }
	//如果两个线程同时到达等于null这一步,然后就可能同时产生好多个对象,因此不是线程安全的
    public static Mgr03 getInstance() throws InterruptedException {
        if (INSTANCE == null) {
            Thread.sleep(1);
            INSTANCE = new Mgr03();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Mgr03.getInstance().hashCode());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }
    }
}

对懒汉式单例模式进行改进
public class Mgr04 {
    private static Mgr04 INSTANCE;

    private Mgr04() {

    }
	//在此处加上了同步锁,虽然不会发生线程不安全的情况,但是由于
	//整个锁的范围是整个方法级的,因此效率不是很高
    public static synchronized Mgr04 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            INSTANCE = new Mgr04();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Mgr04.getInstance().hashCode());
            }).start();
        }
    }
}

提高懒汉式单例模式效率
public class Mgr05 {
//注意此处的关键字volatile是出于JIT可能会出现对编码重新排序的问题,使用该关键字可实现线程之间的可见性
    private static volatile Mgr05 INSTANCE;

    private Mgr05() {

    }
    //该方法不能保证线程安全性,因为此处的判断和下面判断中的
    //执行代码不是保证一体的,当第一个线程执行到同步代码前,第二个线程
    //执行到return语句前,此时已经产生一个对象,这时第一个线程接着执行生成一个
    //新的对象,此时已经产生了两个不同的对象,所以线程不安全,但是此处把同步锁的范围变小了,相应的执行效率应该也会有所提高
    public static Mgr05 getInstance() {
        if (INSTANCE == null) {
            synchronized (Mgr05.class) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                INSTANCE = new Mgr05();
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Mgr05.getInstance().hashCode());
            }).start();
        }
    }
}

解决上一个方案中出现的线程不安全的问题
//该例子是线程安全的
//该方法中使用了双重检查,在
public class Mgr06 {
    private static Mgr06 INSTANCE;

    private Mgr06() {

    }
    public static Mgr06 getInstance() {
        //上面的检查是为了后面大多数的线程做判断如果为空,可以直接进行返回
        if (INSTANCE == null) {
            //双重检查
            synchronized (Mgr06.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    INSTANCE = new Mgr06();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Mgr06.getInstance().hashCode());
            }).start();
        }
    }
}

使用静态内部类方式的单例模式
//加载外部类的时候不会加载内部类,这样同时也可以实现懒加载,实现按需分配
public class Mgr07 {

    private Mgr07() {

    }

    private static class Mgr07Holder {
        private final static Mgr07 INSTANCE =
                new Mgr07();
    }

    public static Mgr07 getInstance() {
        return Mgr07Holder.INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Mgr07.getInstance().hashCode());
            }).start();
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值