单例模式

单例模式定义

Ensure a class has only one instance, and provide a global point of access to it.
也就是说:确保某一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。

单例模式的类图

这里写图片描述

单例模式的分类

单例模式可分为,饿汉式和懒汉式

饿汉式

饿汉式顾名思义,迫不及待的就new一个对象出来,不管你要不要,我自己先实例化一个实例再说,你需要的时候我就给你,不需要的话就放我这.

懒汉式

而懒汉式呢,就是当你第一次需要的时候我才去实例化,你不要我就不实例化

这两种方式有什么特点呢,首先饿汉式在类加载的时候会比较慢,为什么呢,因为类在加载的时候首先要去实例化一个对象,实例化对象肯定比较耗时,但是在获取实例的时候会比较快,毕竟人家已经实现实例化好了,就等着你用了.
懒汉式呢,在类加载的时候会比较快,但是在第一次获取实例的时候会比较慢,原因在于,第一次获取实例的时候,它需要去先实例化,再返回给别人.而且呢,饿汉式是线程安全的,懒汉式是线程不安全的,为什么这么说,试想一下,在高并发的情况下,假设A需要去获取一个实例,在判断是否存在该实例时,返回null,所以这是需要去创建一个实例,但是它还没创建完,这时B也想要一个实例,他也去判断是否存在,结果判断结果也不存在,因为A在获取的时候还没有实例化完成,B就来要了,所以这时候就会产生2两个实例,所以说是线程不安全的

饿汉式代码

/**
 *@DESCRIPTION 饿汉式单例模式
 *@AUTHOR SongHongWei
 *@TIME 2018/8/12-19:14
 *@PACKAGE_NAME test.factory.single
 **/
public class Singleton
{
    //new一个实例
    private static Singleton instance = new Singleton();

    //构造方法私有化
    private Singleton()
    {

    }

    //对外提供一个实例对象
    public static Singleton getInstance()
    {
        return instance;
    }

    //计数器
    private int count;

    //计数器方法
    public int addCount()
    {
        return ++count;
    }
}

懒汉式代码

/**
 *@DESCRIPTION 懒汉式单例模式
 *@AUTHOR SongHongWei
 *@TIME 2018/8/12-19:14
 *@PACKAGE_NAME test.factory.single
 **/
public class Singleton
{
    //new一个实例
    private static Singleton instance ;
    //构造方法私有化
    private Singleton()
    {

    }

    //对外提供一个实例对象
    public static Singleton getInstance()
    {
        if (instance==null)
            instance =  new Singleton();
        return instance;
    }

    //计数器
    private int count;

    //计数器方法
    public int addCount()
    {
        return ++count;
    }
}

客户端模拟调用计数器

public class Client
{
    public static void main(String[] args)
    {
        int count = 0;
        Singleton instance = Singleton.getInstance();//获取实例
        for (int i = 0; i < 10; i++)
        {
            count = instance.addCount();//模拟调用10次计数
        }
        System.out.println("count====" + count);
        Singleton instance2 = Singleton.getInstance();//模拟另一处地方获取该实例并调用计数器方法
        count = instance2.addCount();//     
        System.out.println("count====" + count);//如果两处地方获取的不是同一个实例,那么第二次获取的对象count值应该为1,否则为11
    }
}

输出结果

count====10
count====11

Process finished with exit code 0

客户端模拟懒汉式线程不安全情况

/**
 *@DESCRIPTION 模拟调用单例模式的计数器场景
 *@AUTHOR SongHongWei
 *@TIME 2018/8/12-19:16
 *@PACKAGE_NAME test.factory.single
 **/
public class Client
{
    public static void main(String[] args)
    {
        int count = 0;
        //模拟高并发,同时启动9999个线程
        for (int i = 0; i < 9999; i++)
        {
            Thread thread = new Thread(new Single());
            thread.start();
        }
    }
}
//调用计数器的线程
class Single implements Runnable
{

    @Override
    public void run()
    {
        Singleton instance = Singleton.getInstance();//获取实例
        System.out.println("count====" +  instance.addCount());
    }

}

输出结果

count====1
count====3
count====4
count====2
count====1
count====5
count====6
count====7
count====8
count====9

明显看出结果有两处打印的是1,也就是说实例化了2个对象

适用场合

  • 需要频繁的进行创建和销毁的对象;
  • 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
  • 工具类对象;
  • 频繁访问数据库或文件的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值