这下好了,对象也要共享不让你new了。
单例模式
我们先不谈什么是单例模式,我想其实很多人其实最关心的是什么时候需要用到单例模式?使用单例模式之后有什么提升与益处?
首先我们知道单例单例,可以简单理解为单个实例,而实例化是指在面向对象的编程中,把用类创建对象的过程称为实例化。是将一个抽象的概念类,具体到该类实物的过程。
那么什么情况下会优先、或者强制使用单例模式创建实例呢:
- 数据库连接池,注意: 这里的单例指的是数据库连接池对象,而不是单个连接对象,这点一定要分清。
Spring
中的Bean
,获取实例的时候都是默认单例模式,所以多线程是要注意(面试题警告⚠)。API
接口中的token
、id
的获取,比如百度AI文字识别的accessToken
中的获取,一般该token
有一定的有效期,需要自行管理,当失效时需重新获取的方式,采用单例模式就可以很好的节约资源。- 多个子类想共享一个父类的线程池的业务场景,频繁创建
ThreadPool
应该是不合适的,其实这个时候static
单例化ThreadPool
,注入是比较好的选择(这个例子比较特殊,可能是设计问题高耦合,可以不看)。
单例模式确保某个类只有一个实例,而且是自身创建唯一实例,提供一个全局访问的入口。网上的单例模式的写法大致就是3种:懒汉式单例模式、饿汉式单例模式、登记式单例模式:
- 懒汉式单例模式:在类加载时不初始化。
- 饿汉式单例模式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。
- 登记式单例模式:它的单例在类被装载的时候就被实例化了,内部也算是饿汉式单例模式。
登记式单例模式由于本人不太熟悉,所以在本文中只讲述前两种。
Java类加载顺序
为什么要叫饿汉式、懒汉式呢?饿汉式则可以想象成因为太饿了,在类加载时就迫不及待完成了实例化,但是如果从初始化到线程结束都没有使用过的,就是变成了资源浪费。这里需要拓展下Java类的加载机制:
1 | /** |
从打印的结果可以看到Java类的加载顺序大致是:静态成员/静态代码块
—> main方法
—> 非静态成员/非静态代码块
—> 构造器
饿汉式单例模式
上面讲到了,饿汉式单例是在类加载就是内部实例化对象,并且不允许外部创建实例。饿汉式单例模式的实现也比较简单,记住无参构造器私有化,内部实例化对象,外部通过static
方法获取对象。
我们都知道坤坤是一个对细节把控很有追求的人,从那段舞蹈的诸多细节就能够看出来。尤其是最后的白色吊带滑落,堪称经典之举,坤坤通过有意的小失误将前面表演精心铺垫的「舞王」设定迅速推翻,营造了一种反差萌拉近与粉丝的距离,白带异常的表现也让粉丝们感同身受。
坤坤自从白色吊带表演大火🔥之后,淘宝厂商为了恰烂钱💰纷纷效仿推出「坤坤同款异常白色吊带」、「坤坤潮流异常背带」的爆款产品。谁知道厂商还没开始恰烂钱💰的时候,坤坤就机智的把「坤式白色吊带」和「白色吊带异常」申请了发明专利、外观设计专利、实用专利,将「坤式白色吊带」这个商品
和「白色吊带异常」这个艺术作品
的所有权把握在了自己手里。「白色吊带异常」的表演不允许外界直接模仿、抄袭,必须先向坤坤申请,支付一定费用才购买了「坤式白色吊带」对象
的licence
后才可以表演「白色吊带异常」,并且使用完后要进行归还,这样就能确保只有一个白色吊带在外部商演能够很好的锁定。孙哥烂钱💰都恰得没这么6嗷~
1 | /** |
1 |
|
优点:
- 线程安全
缺点:
- 类初始化实例化对象后未被调用则是浪费资源的表现
懒汉式单例模式
坤坤虽然唱跳俱佳,但也耐不住是条懒狗🐶,只有等到电话、message、inbox连环催,他才开始发货。
1 | /** |
优点:
- 单例实例在第一次被使用时构建
缺点:
- 不加锁的话,存在线程安全问题,即使加了锁,对性能也产生了影响。
注: 为什么说懒汉式单例模式是线程不安全的呢,假如有两个客户线程
准备购买「坤式白色吊带」和「白色吊带异常」进行商演,第一位客户提出申请,坤坤刚回复马上交付,另一位客户的聊天窗口弹了出来也问能马上交付吗?坤坤一急立马把「白色吊带」和「白色吊带异常」的licence
的交付第二位客户,交付完之后坤坤想到第一位客户也在等待,于是又把新的「白色吊带」和license
交付给了第一位客户。然而现在已经有两个对象
游离在外了,坤坤表示头很大。
坤坤发现自己亲自处理不但没牌面,而且容易出事情,但是交给经纪人又不放心,思来想去坤坤还是决定把这项业务交给哥哥孙笑川打理,自己则脱离去做更纯粹的音乐去了。
1 | /** |
优点:
- 线程安全
- 单例实例在第一次被使用时构建
缺点:
- 暂无
还是孙哥办事靠谱嗷,毕竟恰烂钱💰带师~