设计模式-02单例模式

文章详细介绍了Java中实现单例模式的多种方法,包括饿汉式(静态常量和静态代码块)、懒汉式(线程不安全和线程安全)、双重检查、静态内部类以及枚举方式。每种方式的优缺点和线程安全性都进行了分析,其中枚举方式被认为是最佳实践。文章还强调了单例模式在资源管理和性能优化中的重要性。
摘要由CSDN通过智能技术生成

单例模式

实现方式

  1. 饿汉式(静态常量)
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.创建单例对象
    private static final Singleton INSTANCE = new Singleton();
    //3.获取单例对象的静态方法
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

总结:简单方便,通过类装载机制解决线程安全问题。
缺点: 如果使用过程中没有使用到改单例对象,会导致内存资源浪费,起不到懒加载的作用。
推荐指数:☆ ☆ ☆

  1. 饿汉式(静态代码块)
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.创建单例对象
    private static final Singleton INSTANCE;
    static{
       INSTANCE = new Singleton();
    }
    //3.获取单例对象的静态方法
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

总结:和基于静态变量的方式相同。
推荐指数:☆ ☆ ☆

  1. 懒汉式(线程不安全)
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.定义单例对象
    private static Singleton INSTANCE;
    //3.判断单例对象是否为空,为空则先创建然后返回对象
    public static Singleton getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

总结:虽然解决了懒加载的问题,但是存在严重的线程安全问题
推荐指数:不推荐

  1. 懒汉式(线程安全,同步方法)
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.定义单例对象
    private static Singleton INSTANCE;
    //3.判断单例对象是否为空,为空则先创建然后返回对象,通过synchronized保证线程安全
    public synchronized static Singleton getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

总结:解决了懒加载的问题,避免了资源的使用浪费,但每次线程获取单例对象都需要加锁,性能底下
推荐指数:☆

  1. 懒汉式(线程不安全,同步代码块)
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.定义单例对象
    private static Singleton INSTANCE;
    //3.判断单例对象是否为空,为空则先创建然后返回对象,通过synchronized同步代码块
    public static Singleton getInstance(){
        if(INSTANCE == null){
            synchronized(Singleton.class){
            	INSTANCE = new Singleton();
            }
        }
        return INSTANCE;
    }
}

总结:有人提出,每次获取单例对象都需要加锁的优化方案,在创建对象的时候加锁,但是当多线程获取单例对象的时候,可能存在多个线程都进入if判断语句中,导致获取对象并非单例。
推荐指数:不推荐

  1. 双重检查
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.定义单例对象,volatile作用是强制把线程内存中的数据刷回主存
    private volatile static Singleton INSTANCE;
    //3.判断单例对象是否为空,为空则先创建然后返回对象,通过synchronized同步代码块
    public static Singleton getInstance(){
        if(INSTANCE == null){
            synchronized(Singleton.class){
                if(INSTANCE == null){
                 	INSTANCE = new Singleton();   
                }
            }
        }
        return INSTANCE;
    }
}

总结:通过双重检查保证了线程安全也做到了懒加载
推荐指数:☆ ☆ ☆

  1. 静态内部类
public class Singleton{
    //1.私有化构造函数,防止new对象
    private Singleton(){}
    //2.定义静态内部类,静态内部类只有在真正使用到的时候才会装载,而类装载是线程安全的,避免了线程安全问题
    private static class SingletonInstance{
        public static final Singleton INSTANCE = new Singleton();
    } 
    //3.获取单例对象
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}

总结:通过静态内部类的装载机制实现了线程安全问题,而且静态内部类只有在真正调用getInstance()方法时才会真的加载静态内部类起到了懒加载的作用。
推荐指数:☆ ☆ ☆ ☆ ☆

  1. 枚举方式
public class TestEnum {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        instance.sayHello();
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);//true
        System.out.println(instance.hashCode() == instance2.hashCode());//true
    }
}
enum Singleton {
    INSTANCE;
    public void sayHello(){
        System.out.println("hello");
    }
}

总结:枚举创建单例的方式被《Effective Java》的作者认为是最佳实现单例的方式,使用简洁,无偿提供了序列化机制。
推荐指数:☆ ☆ ☆ ☆ ☆
使用举例:

public class Main {
    public static void main(String[] args) {
        DBConnection con1 = DataSourceEnum.DATASOURCE.getConnection();
        DBConnection con2 = DataSourceEnum.DATASOURCE.getConnection();
        System.out.println(con1 == con2);
    }
}
//枚举类,实现单例
enum DataSourceEnum {
    DATASOURCE;
    private DBConnection connection = null;
 
    private DataSourceEnum() {
        connection = new DBConnection();
    }
 
    public DBConnection getConnection() {
        return connection;
    }
}
class DBConnection {} 
单例模式注意事项和细节说明
  • ​ 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须记住使用相应的获取对象的方法,而不是new
  • 单例模式使用场景:需要频繁的进行创建和销毁的对象,创建对象时消耗过多或消耗资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如:数据源、session工厂)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值