Java面试--单例模式

面试题:设计模式有了解过吗,单例模式特点是什么、为什么使用单例模式、能手写出来吗?实现单例模式有哪些方法(大疆、百度面试题)
面试题:如何确保单例线程安全(阿里面试题)

一、单例模式:
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
二、为什么使用单例模式呢:
当我们需要确保某个类只要一个对象,或创建一个类需要消耗的资源过多,如访问IO和数据库操作等,这时就需要考虑使用单例模式了。
比如:当我们使用多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行
数据库连接实例主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为用单例模式来维护,就可以大大降低这种损耗。
三、手写单例模式呢:
1、懒汉式,线程不安全:
这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。

public class DanLiMoShi1 {
    private static DanLiMoShi1 instance;
    private DanLiMoShi1 (){}
    public static DanLiMoShi1 getInstance() {
        if (instance == null) {   //如果有了实例了,就不需要要创建了
            instance = new DanLiMoShi1();
        }
        return instance;
    }
    public void SayLove(){
        System.out.println("Love You Baby!");
    }
}
//测试一下
public class Test1 {
    public static void main(String[] args){
        DanLiMoShi1 danli1 = DanLiMoShi1.getInstance();
        DanLiMoShi1 danli2 = DanLiMoShi1.getInstance();
        if( danli1 == danli2 )
            System.out.println("我们是一样的");
        danli1.SayLove();
    }
}
//运行结果:
//我们是一样的
//Love You Baby!

2、懒汉式,线程安全:
必须加锁 synchronized 才能保证单例,但加锁会影响效率。

public class DanLiMoShi2 {
    private static DanLiMoShi2 instance;
    private DanLiMoShi2 (){}
    public static synchronized DanLiMoShi2 getInstance() {
        if (instance == null) {   //如果有了实例了,就不需要要创建了
            instance = new DanLiMoShi2();
        }
        return instance;
    }
    public void SayLove(){
        System.out.println("Love You Baby!");
    }
}

3、饿汉式,线程安全:
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

public class DanLiMoShi3 {
    private DanLiMoShi3() {
    }
    private static final DanLiMoShi3 single = new DanLiMoShi3();
    public static DanLiMoShi3 getInstance() {   //静态工厂方法
        return single;
    }
    public void SayLove(){
        System.out.println("Love You Baby!");
    }
}
测试:
public class Test3 {
    public static void main(String[] args) {
        DanLiMoShi3 danli1 = DanLiMoShi3.getInstance();
        DanLiMoShi3 danli2 = DanLiMoShi3.getInstance();
        if( danli1 == danli2 )
            System.out.println("我们是一样的");
        danli1.SayLove();
    }
}
//运行结果
//我们是一样的
//Love You Baby!

4、双检锁/双重校验锁(DCL,即 double-checked locking)
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。

public class DanLiMoShi4 {
    private volatile static DanLiMoShi4 singleton;
    private DanLiMoShi4 (){}
    public static DanLiMoShi4 getInstance() {
        if (singleton == null) {
            synchronized (DanLiMoShi4.class) {
                if (singleton == null) {
                    singleton = new DanLiMoShi4();
                }
            }
        }
        return singleton;
    }
}
//测试
public class Test4 {
    public static void main(String[] args) {
        DanLiMoShi4 danli1 = DanLiMoShi4.getInstance();
        DanLiMoShi4 danli2 = DanLiMoShi4.getInstance();
        if( danli1 == danli2 )
            System.out.println("我们是一样的");
    }
}
//运行结果:
//我们是一样的

为什么这种能提升性能呢?
这里我重点讲下:如果直接加锁,那么10个线程来了,那这10个线程需要排队;但是采用双检锁/双重校验锁的方式,10个线程来了,如果已经有实例了,直接返回实例,这样就不需要排队了,从而提高了性能。


Java面试的完整博客目录如下:Java笔试面试目录

转载请标明出处,原文地址:https://blog.youkuaiyun.com/weixin_41835916 如果觉得本文对您有帮助,请点击支持一下,您的支持是我写作最大的动力,谢谢。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北极星小王子

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值