设计模式之——单例模式

相关知识:

通常设计模式有23种,主要分为三大类:

  • 创建型模式(5种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式(7种):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式(11种):模板方法模式、中介者模式、策略模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、解释器模式。

前言:

单例模式:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。

特点:

  1. 单例类只有一个实例对象
  2. 该单例对象必须由单例类自行创建
  3. 单例类对外提供一个访问该单例的全局访问点

注意:

普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。所以单例模式的构造函数应是私有的。

实现:

项目结构:

普通类Apple:

//项目结构图中普通类

package com.dp.singleton;

public class Apple {
}

饿汉式单例实现类HungrySingleton:

//项目结构图中饿汉式单例实现类

package com.dp.singleton;

public class HungrySingleton {
    private static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton(){

    }
    public static HungrySingleton getInstace(){
        return hungrySingleton;
    }
    public void print(){
        System.out.println("我是饿汉式单例模式...");
    }
}

懒汉式单例实现类LazySingleton:

注意:如果编写的是多线程程序,则不要删除代码中的关键字 volatile 和 synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。

//项目结构图中懒汉式单例实现类

package com.dp.singleton;

public class LazySingleton {
    //保证 instance 在所有线程中同步
    private static volatile LazySingleton lazySingleton= null;
    //private 避免类在外部被实例化
    private LazySingleton(){}
    //getInstance 方法前加同步
    public static synchronized LazySingleton getInstance(){
        if(null == lazySingleton){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
    public void print(){
        System.out.println("我是懒汉式单例模式...");
    }
}

测试类TestMain:测试结果看代码中注释打印部分

//项目结构图中测试类

package com.dp.singleton;


public class TestMain {

    public static void main(String[] args) {
        //一般创建对象测试
        Apple app1 = new Apple();
        Apple app2 = new Apple();
        System.out.println(app1 == app2);       //false
        //饿汉式创建对象
        HungrySingleton hungrySingleton1 = HungrySingleton.getInstace();
        HungrySingleton hungrySingleton2 = HungrySingleton.getInstace();
        hungrySingleton1.print();  //我是饿汉式设计模式...
        hungrySingleton2.print();  //我是饿汉式设计模式...
        System.out.println(hungrySingleton1 == hungrySingleton2); //true
        //懒汉式创建对象
        LazySingleton lazySingleton1 = LazySingleton.getInstance();
        LazySingleton lazySingleton2 = LazySingleton.getInstance();
        lazySingleton1.print();  //我是懒汉式单例...
        lazySingleton2.print();  //我是懒汉式单例...
        System.out.println(lazySingleton1 ==lazySingleton2);       //true
    }
}

总结:

实例化方面:懒汉式默认不会实例化,外部什么时候调用什么时候new。饿汉式在类加载的时候就实例化,并且创建单例对象。


线程安全方面饿汉式线程安全 (在线程还没出现之前就已经实例化了,因此饿汉式线程一定是安全的)。懒汉式线程不安全( 因为懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的,比如:public static synchronized Lazy getInstance(){   if(lazy==null){  lazy=new Lazy(); } 如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生) 。


执行效率上:饿汉式没有加任何的锁,因此执行效率比较高。懒汉式一般使用都会加同步锁,效率比饿汉式差。


性能上:饿汉式在类加载的时候就初始化,不管你是否使用,它都实例化了,所以会占据空间,浪费内存。懒汉式什么时候需要什么时候实例化,相对来说不浪费内存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值