浅谈单例模式的实现方式! @& U( m+ Y; ]) r+ k
单例模式(来自菜鸟教程)
8 g+ [" R4 q# j3 o
( u0 B0 b) z6 A! i' J! @单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
+ b% Z# o6 m* V2 c0 U+ R4 T" {单例模式的要求- @9 M% N, `( D! s
* y$ B, x0 \" K: p' j: _
构造方法必须私有化(确保只有自己能创建)
; o0 ~$ t7 p/ [$ M以静态方法返回实例(外界不能通过new来获取到对象)
5 M+ M' W5 C8 B7 \, [8 r确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
, C! y! t# ^, h5 q9 n9 u" D单例模式的实现
6 i8 L4 O9 D0 j& A( [
# f( u1 E- j6 r- M( c& {* W9 H; `1、懒汉式(线程不安全)
4 [; e& P, \2 o& `' v5 Y
8 m0 R, j% R# R( B2 p: Z描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
) g/ v- O, W! J. ^1 S//懒汉式(线程不安全)
9 M$ a/ |: {* tpublic class Singleton { : G) ]1 ?8 @' i7 e+ ^
private static Singleton instance;
]1 g% a6 t ]0 r
5 ]6 U0 H7 g2 m; B6 Y' C" ^ private Singleton (){}
& H' I w p, l. E- _7 a
9 t" t% _- `1 a: X( @6 T public static Singleton getInstance() { ( W, T" b7 N, E
if (instance == null) { ' c9 G) a# R) O5 s4 p
instance = new Singleton();
# K T9 B# Z1 }9 H }
1 d, r5 z- s% A; P return instance;
/ l8 ?2 e) b0 F& c5 r } : z, q: C0 P9 G& @
}- q$ c7 C) C. K! E
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)7 F9 Y" Z6 A6 s' M
public class Singleton { 1 I# d3 p- H: d
private static Singleton instance;
( F o; S( [. M2 ?7 @- m: o: b7 Y. i) d3 F+ {9 C
private Singleton (){}
! z$ k( U8 v4 M; v1 x2 i; {) ~) s2 l9 g; j3 u+ x
public static synchronized Singleton getInstance() {
3 J1 o! X" B* W+ K, c if (instance == null) { % G! l. [. Z$ l
instance = new Singleton();
& W3 q3 x/ {9 Q; i6 E$ x8 }5 X: [1 I }
3 U5 C4 l( L' J; g3 x return instance;
/ Y9 _3 y- w0 h$ ~; H } , @; z; \" k9 s% d- j
}$ L0 k5 S( p( j8 J& C* l
9 l* D* g+ B, j+ c6 f% R3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 & V) `2 E: X, ?2 i! c8 K2 [3 t
//双重校验锁- O8 E% j8 ^$ [+ a
public class Singleton {
% H: Q' ?3 `2 K& S private volatile static Singleton instance;
9 h; J0 {. I8 K$ t4 `0 ~9 u2 u! d/ p1 S3 u2 }; O0 d
private Singleton() {; F+ f/ [ A0 H, b# Q
/ T$ K B$ _, b* E: ? }3 |: n# A- h3 g9 \5 P
. ?& r# W7 K: {7 H( d4 h8 U
public static Singleton getInstance() {+ }9 V2 v3 `) H+ ]# m# t
if (instance == null) {
3 ~0 \" ]6 ~, b synchronized (Singleton.class) {
7 [1 e( p2 Z2 N8 V$ s if (instance == null) {
& ]+ T3 D0 U: c9 W- |( j) j+ j instance = new Singleton();7 }8 h3 R7 A( S) w/ r, b! D
}! W2 N; l' }+ I4 |$ J# Z; {! ~4 w
}
8 _3 \+ e& K6 l* l }1 {; E' d$ G3 i
return instance;
3 M# ^5 G) C/ S! {7 V }
3 F( R* V$ |( }$ t; F4 H; Z9 \}
1 h8 p& K# L5 P2 K# G# J# Z# v7 l% n7 S1 z9 U3 H: y; T
7 w6 P3 q6 x+ B: z I7 J& c' _5 n
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
$ w! j, u2 `# ?- _//饿汉式
; ^# C, b {0 }/ kpublic class Singleton {
7 b( p2 I, Q# _ private static Singleton instance = new Singleton();+ Y4 @! Q5 @5 B8 T
/ A* }; Z' j# c private Singleton() {9 a3 I J' ?7 g& L4 L
% X, r b8 H( x- u/ c }
$ V6 a( Z8 z" q) X3 `# ~8 h3 A; p% B: J) {! C. `0 G. o- p+ D
public static Singleton getInstance() {0 W" o. ?( b/ N# `9 d' v5 N
return instance;+ a4 |' ~2 a' \; s6 ?
}& S& l! O; C( a. A1 U, e
}
' N1 C$ Z! S$ I) L: h
& {9 W7 E d4 K
, a/ X1 |- q, X& ?& ?- J' s5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
5 }0 e) [! v; J0 m/ v) i3 }, wpublic class Singleton {% g- |6 ~3 z$ [8 A" t( N) @& a: ~, X
private static class SingletonHolder {; x% } Y; j9 c. o/ [ G) _' o6 @
private static final Singleton INSTANCE = new Singleton();
+ z( a2 N) O- `+ y: h }! G' e3 [6 d/ u; [
+ b# D6 w9 G5 p# A( H8 A
private Singleton() {
% y: J2 _2 Y# d6 h5 P6 M" v1 n5 e) U! _9 @6 q9 \" D' [% n6 X
}' k0 n3 h+ n+ w& y' s
; a* P) e0 s+ `9 {4 z2 t
public static final Singleton getInstance() {
: _8 }/ @0 M7 M, B return SingletonHolder.INSTANCE;
/ | O% o7 `* C) d* j }
, H8 Z* L4 `& s# U. b}$ {2 E$ t; }2 U& C0 `
/ p' g0 D; M7 J3 |4 ?% `, N3 |3 o4 \6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 : t) E# i* i. x1 ]. F% B
//枚举
/ @& Q5 E4 ?5 }! o9 R& {0 }( J% xpublic enum Singleton {. A* Z+ @3 n* F7 P V2 U
INSTANCE;3 ^$ l; D* P Z1 e
U9 l t- H. b4 y3 L' g. m: n
public void whateverMethod() {
6 s' O2 G2 e. R( u' B/ }- Y$ @. T/ s/ R& A' D7 R1 D! o& w2 v
}
4 ~1 f, ^$ G0 L6 l! m9 ]}- ]. v' c3 F3 W( B
& f2 T" m" x9 A5 m- P) `6 {& l' L* V5 ?
总结
0 {0 v7 Z8 r. B5 I' ?. \9 v( u7 g, p, m m' z2 u. [, A
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。+ W" {) z$ c2 {* G2 p
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~1 Z( x4 K, a) I7 g+ q
————————————————' H+ Z c& v1 `$ l6 v% y: h( \* N
: M9 G+ Z R! k, R
8 h0 m1 F2 g7 E. V W6 m+ j' K9 ?- b$ Y. n+ ^
+ f0 K3 P4 v: r$ c
3 ?' G! G1 h% [+ j; L- R2 K! _* j6 E8 o+ I8 s* b, |
0 w5 e0 e8 s* E
0 S* j! v7 |. L/ ~
* y, ~/ }3 m" i原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764+ t9 K7 S. ?, R9 O/ T$ y, O
1 b1 n1 _. A, A8 {
& u$ V9 I- a w9 f& [# [) I |