浅谈单例模式的实现方式) ~' V3 a2 h5 Q
单例模式(来自菜鸟教程)" L! L3 _: {2 Y& T
& }: t. W! \; ?5 n$ q. N6 S5 D1 M
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。! T$ g. u+ L& k2 i/ Y' l
单例模式的要求
: K, I0 [4 d/ s6 z
% J' ]6 Y5 A0 m) R7 O构造方法必须私有化(确保只有自己能创建)3 _$ E# a7 D! r- o
以静态方法返回实例(外界不能通过new来获取到对象)
0 k( K6 K8 I) y, f, F% g确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)2 C8 K. v7 j" X% E
单例模式的实现1 c5 E2 _& T& S2 c4 o$ S0 `3 |
) B1 |6 |7 ]( {5 E3 h5 k3 t2 p# u* Z
1、懒汉式(线程不安全)
" ~9 C0 V5 |9 {. d( k3 X/ k7 R& ^ ?6 B" h' u6 D/ V `0 \
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
& d) u! j; _) s2 s//懒汉式(线程不安全)
( l* }& U& c5 r7 Cpublic class Singleton {
, i; q6 N$ Z# h. q private static Singleton instance;
0 t; Q9 R7 O$ Y) s* p9 \7 U, T$ b/ V2 {, v4 Y
private Singleton (){} 6 m2 \8 ~; I6 E3 t; \8 @; X
0 k. M) k0 N$ w, P2 K W9 e* x public static Singleton getInstance() {
0 h" E$ r* }/ a! n3 ?: y if (instance == null) {
3 j3 q, G" t; ~; W instance = new Singleton();
8 W1 j* T+ ~* p* k) _* i } # C" `+ b, a# y9 W4 F
return instance;
$ |# q+ l( x1 b& s+ u9 f& | }
( Y. R* w( x- X8 a& F}7 q/ D' q8 m: x9 w/ R9 m8 f
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)! e2 n# O& ^# {" C
public class Singleton {
7 S+ k2 Q9 ~* w4 `$ p+ ]! g private static Singleton instance; ( d+ Q* ~) s) q! f" q/ O
$ n, c" Y0 x1 j
private Singleton (){} / k' P* @: V7 K
U: f5 k7 |6 r3 y0 j6 \( U
public static synchronized Singleton getInstance() { + l# j0 R* G3 Q; `
if (instance == null) { % ?3 d0 Q' J1 Z6 D
instance = new Singleton(); " E% Z' z' l* l: p$ l7 F& t
}
/ T% w: }( x# k3 N; u* E* r return instance;
8 A1 C3 F; f: X }
& H/ l0 `7 j/ S5 G0 I7 C}
( \- m+ s" r+ p: J4 F. L! M7 K5 W& D/ C, B2 A# c# D: n
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 & h* c9 c1 Q4 [# J2 a
//双重校验锁* s% H/ s8 i3 t; ]
public class Singleton {
% \/ C% L2 d: ~ private volatile static Singleton instance;
4 C9 K9 `) {6 v
* U! M: M. s# f5 k- X( Y' c; c4 u: P private Singleton() {
) @7 `. M. v4 s4 S$ }
8 L4 `% i h/ [+ u2 M7 ?; U }
6 E( ]5 o2 i* d( O- L0 V& B9 f) k1 a4 z. G% y2 o7 p
public static Singleton getInstance() {
/ g9 M$ r3 b. z7 ~ if (instance == null) {
: Q! a& o/ k5 n- ~0 R synchronized (Singleton.class) {4 h4 ^+ P; d6 ~' U- @0 {8 {
if (instance == null) {; Q9 I* B' B5 _( t7 b5 U; j5 V
instance = new Singleton();
; n. T3 y% z9 p! ?8 U" A' H' h }# ~# k( B3 ^% V5 _ m5 @" Z
}3 ~9 S" Z, C# B. Q ^
}4 w" ?+ s7 c+ V7 T, F. K
return instance;
( d, J- q2 S/ r$ p# f& i8 T O' Y }
G) b# l6 a0 h9 r" p: L3 X e}( T9 I/ k$ W+ }# i0 b
T$ n6 K3 ~1 o) B1 i
. e2 a. N0 o9 w! O; y# P4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
6 S, t' ]: D+ w4 {/ P1 n2 f//饿汉式' C ]; l1 J( z2 x5 ^0 Z
public class Singleton {
& P- {6 X* K6 G' @" g private static Singleton instance = new Singleton();
3 w. C3 P+ y9 }' S( S# y
( U& w3 z5 l- r' I1 c8 n private Singleton() {
' a9 [3 M& ~5 M3 [' `, w
/ k5 W+ a1 `) g }
9 }' c. o* s4 |, i7 v" I* d4 s3 q7 s. W n: Y% Y, Z
public static Singleton getInstance() {$ l) s' m$ {' E9 U) v" f. \
return instance;: _; G+ O, y) Q7 W
}( W) W6 o d3 Q# y; ]3 V1 A
}
& J9 a0 b) {; {4 w0 o: l# G& }! t4 v+ e# e* w, }3 r! h( l( z8 N
* R" g0 b" {+ E& F5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类0 x5 s' c1 u( a& ~) f% `/ ]
public class Singleton {8 w- r- |* h( m9 M* ^( u
private static class SingletonHolder {+ C9 @5 K* F3 I0 a
private static final Singleton INSTANCE = new Singleton();6 h) M( G3 c m+ P, R
}2 f, D, y, z& r
, i+ W# `. N# s, s! x- u! X private Singleton() {, K# _ i+ o6 c! `
" W6 _1 Q, L; q, c) p3 Z }1 ^4 E* [$ R1 I# ?; M/ A
% `/ i2 a* E+ v5 W) ]7 P. R4 H
public static final Singleton getInstance() {
. v' Q8 ~! {: I$ Z; Y) A return SingletonHolder.INSTANCE;6 {& o" {3 S0 @) J7 {
}
7 F/ T) d: ?1 R6 B5 S}
( n- z- G. v9 i$ _& x
% u; {: ?3 u! s* |) U" f" V6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
, p7 |" _, `6 r& X( H& m4 q8 W, j//枚举
' C5 p# ^/ e( X/ ]public enum Singleton {9 h: Q2 r1 c) M1 L( N" K
INSTANCE;
4 d% U3 s4 S. b2 D! C5 g$ V& O) D |5 |' s Y0 @- E6 l
public void whateverMethod() {# h5 H* o6 N) \
& g' O3 U4 O& ~ }
# ~( q9 d9 P& X% P; M+ N- @}
8 {) B, B5 C8 Y% a8 {
9 [0 B4 X- N4 d. K. t# E" v3 Y. K$ `/ ]: f. M% Y1 B5 V {
总结0 h$ p4 l$ _% p# x
1 S( C* s. |/ N# _一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。9 C& W" |4 q! }3 ^! V4 I
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~9 T5 B3 y1 m3 c/ _1 T
————————————————8 }0 Z" _# k1 B! O5 W
4 n9 X/ [9 S8 p* D5 l( [% u
# G3 ]% f- F( G# j1 `: d/ q
. Z1 j1 \ h' s& v4 @. n. l
* V$ E4 N8 s; j) `, Q
1 W+ c5 E! u% S u& N$ e8 ?$ A5 y- J; b/ \
! p! M& P6 ?; L' K& w& e
' e+ C. [% K! \: K9 r/ u
6 m- e. [" z7 a2 m# S
原文链接:https://blog.csdn.net/weixin_37686415/article/details/1051647640 [- T0 B2 m3 E0 o" V: o
. {' ?3 y3 \) A% [, n
4 \& @" H$ s( Q
|