浅谈单例模式的实现方式
+ o7 X# ^: m$ C8 K5 D5 I: y" D单例模式(来自菜鸟教程)
3 h5 d5 w" ~8 O }3 b+ Z" \
/ f$ C3 K6 k& z; C# U单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。: Z; |. _% Y+ l/ O& g
单例模式的要求* c( g' F' g* ?3 @% m& r
2 e3 r8 m. P0 t6 B7 p构造方法必须私有化(确保只有自己能创建)
3 j9 o0 z* i4 ]; X; I以静态方法返回实例(外界不能通过new来获取到对象); M6 S5 D# b5 j$ B/ i/ m: G. I7 u
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
+ l6 v7 E9 z7 W) p+ T' x单例模式的实现0 w1 d0 Z2 J. D$ M% t
* n4 V- M. Z# h; m1、懒汉式(线程不安全)4 r, z: m# |8 s
6 t/ q( C7 x" H+ S9 p' b$ Y
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
+ j# u+ R ^! O( c7 k5 u5 G7 n# L//懒汉式(线程不安全); t; Z4 l4 M2 u; i! X4 |/ ?
public class Singleton { * z' @$ K1 x8 |
private static Singleton instance;
! v$ a: v/ s m# r
7 \2 M5 Y* u- w K private Singleton (){} : B% S) Q+ w8 z) U- y$ {3 i" T j
3 I4 W' u4 R$ P% u, Z" |# r7 W9 w L
public static Singleton getInstance() {
# P t/ ~* M# G' I: B5 q if (instance == null) { # _8 H2 v# b, s" s% T' w) g
instance = new Singleton(); $ s( _" \" f$ {. l* @
} # d# D [7 M9 H4 H: t. e) Y' [
return instance; 3 _& H' a$ ^4 B+ ~" \: a# F
} 8 O: h" ]/ r7 |( t# X
}; D u( J& P# E
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
9 U! \' h5 P7 k \# |$ c4 Mpublic class Singleton { & H! T; S- ]8 }% T5 Y9 n
private static Singleton instance; / b4 s) S( X! X. W& U
% w& w: H6 [- Z( Q private Singleton (){} % P8 X, v! [# |) i0 \
1 J+ R$ R* I: J& r public static synchronized Singleton getInstance() { ( |! b9 ?' p/ v( i
if (instance == null) { ! N7 X- K3 K& W2 K$ O) F: y
instance = new Singleton(); - D; C. i4 T# H5 D; p1 f0 t ]5 N( L
}
* W/ O8 x* C1 Y' b9 q% f* n return instance; ) _" @+ U* T! ?# z' t
}
+ c7 G" P! r+ I' K: R}
) d V* Q( s+ j9 o" T; X7 g) r/ l5 \7 a+ K& q: m$ O* I6 b" V; d8 U
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 # A3 }/ y3 L T1 D" o. b
//双重校验锁' ]3 S3 Q& ?+ Y6 B
public class Singleton {! Z5 V' f7 r- J: h& L& M. ]6 f1 I9 D/ C
private volatile static Singleton instance;4 l) A" c# w% D, y) j( @
8 H9 S- S( u8 i+ L0 C
private Singleton() {
0 n" d- b' H- j) h" e- k% f3 F) d( O; F8 K* E
}1 T- P/ z4 o1 ]9 K/ x" j: X
8 ?- k9 r6 O# p, e public static Singleton getInstance() {
# x- E3 L; S# j1 U if (instance == null) {& p4 F# G7 C5 @2 g
synchronized (Singleton.class) {
7 t- d% x4 D$ |8 [" p: ^; \1 J2 }! L if (instance == null) {2 [, u0 N) ]6 N6 z
instance = new Singleton();
" f5 L3 G0 ^& ]* C" y( i }4 V( Z* k; ]- J* W \3 r/ R
}
7 u& I9 b4 U. g0 N5 X( Z* X }
# | x2 \" v( k& L" V5 Q return instance; V6 U$ b6 K/ A
}
' B8 k$ I& B, K8 k7 g4 ^$ u}
A) |$ e4 N6 i8 |
) b1 [! n$ B6 q. p$ f
2 Z) V2 T8 J+ ?% L4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 3 F) h3 V1 z) H
//饿汉式
3 q: R; X% r9 xpublic class Singleton {
& C# t l# f) G+ B: ?$ V! Y4 I private static Singleton instance = new Singleton();7 }: `; S2 ~! O; _* y% J
# m0 I8 r4 |% p, y private Singleton() {$ C% N3 U. {: }4 A- S
9 r, Z. w. m3 P$ j1 { }
9 V- m X# W& M; U' Q7 F
% R% t. I; J3 C1 m- K public static Singleton getInstance() {
" R. z' O6 ^9 u; u return instance;3 y! j# E/ w+ B7 U6 M2 }$ R
}
0 j& e% r4 s% ^5 H}
3 q* W- d" ^! b! N/ T2 u( k5 w# _/ A/ W7 J
6 ~: ?4 x- D4 I5 a3 R; E/ n0 R X5 ]5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类: }% y6 w0 h0 e- k# o8 T$ h
public class Singleton {
7 j& b( C# @; f5 @% T* W# e private static class SingletonHolder {
$ Z$ Y; Y( Y' Z3 b9 S, L, P private static final Singleton INSTANCE = new Singleton();: r' x, w6 G: W, m7 O3 b) g( J
}
* P! f0 R: v) O( g) I3 Z" ^% r3 e7 e# V. L
private Singleton() {# L& i3 P+ b& T+ z1 o/ I
! C8 H- ~/ j( }- H9 ?3 U% N8 |
}
4 x( o3 f* W7 s0 I, w0 H
' ^" `; M: O6 p1 a8 } public static final Singleton getInstance() {
: h( T* J: t( d( W3 O$ y* X return SingletonHolder.INSTANCE;; v6 U/ C# M8 n7 x! P( n# V
}; b) Y/ M0 U9 R
}
: D$ k- e2 `' n$ b
6 o- F: z$ z! G8 \6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
+ X: h/ Y$ |$ g//枚举6 l/ F, [" ^) d" g; Z) B) k, w. p1 j
public enum Singleton {
6 o2 y0 e1 N: f m- H9 e+ \ INSTANCE;
; r, n2 e' [! g9 M1 \5 S; `- A6 O. Y5 F; s2 N
public void whateverMethod() {( B7 J; Y" T& z+ I8 f* ^- Q* i2 X L0 b
- Y \' v8 i* N2 Y0 a1 K% K
}
, v& w4 W( d C0 ]5 F/ X9 e}( f1 D7 p6 A, b6 X9 f) g4 P0 i! L( `
! o6 C) w4 r1 w9 z
# o! w) O l: z3 J- O: ]总结
/ `9 a9 t# F+ m% s+ v) R1 X9 g0 A/ Z
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
7 c X1 x1 ?$ N) E1 FPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
( [9 i; x* w# }! ]8 d; `————————————————& F G! S2 B3 F. A7 o/ V9 G
% G2 Q" t* V. i/ E7 E5 j
1 O, M* R& _* ]( D% k
# J; Y V% Y1 Z( H% |. J! B* W
3 J& g+ B8 Z& G
, O2 B4 r( j4 _
% K1 O% r! U" d" c1 u# ?* m8 M% j& @# v
- |$ l8 d$ J% V/ F- m- W9 M5 `
% `& ]) o, l; u9 m+ E( z+ `2 `* h原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764. G9 i/ W* X: X7 I6 T; B+ c' |
4 E3 Z3 H% R# x2 l7 e0 Y
) l8 u' z2 n7 l9 q& L/ j, u
|