浅谈单例模式的实现方式/ O$ Z$ I) ^% b, X4 E. [* N
单例模式(来自菜鸟教程)% g. Q0 X; A! n; o
9 A/ r% z0 k D# s5 m. f+ m单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
, K. B& Z+ w( S" H, N单例模式的要求
( {9 r2 V, N$ k8 v, \5 V( N$ n5 L0 k
构造方法必须私有化(确保只有自己能创建)
7 ~/ [3 h6 A/ \以静态方法返回实例(外界不能通过new来获取到对象)2 N( n1 j$ t% r4 [: Z% w: n
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象). b6 s1 `5 G7 a# W
单例模式的实现6 B, f! I6 }4 B+ a5 k t/ z X
* p! \, D1 Z% P0 ]1、懒汉式(线程不安全)/ j; y. \& l+ p: [( j! I
3 [$ b) a3 a2 ~6 M3 v
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
2 K0 O/ n1 n2 k" b8 _ |8 o//懒汉式(线程不安全)
2 w8 |, k% D9 W4 wpublic class Singleton {
; C+ l; o$ u5 @7 M. Y private static Singleton instance;
% I9 z8 A! J$ n* R6 z8 t2 _) T' `) q$ v' ~
private Singleton (){}
3 a# O/ W2 Z/ n+ f# I/ o9 ~) m+ g1 b- [- S l6 z
public static Singleton getInstance() {
( |8 K/ E7 p- M! ?* t: L, t if (instance == null) {
2 i8 H# k1 j) {1 w: X7 g8 W! v instance = new Singleton(); . B4 g; ~. H: V3 C& g7 }, F
} : ?$ p) B+ T/ \
return instance;
: G7 P, i, t# e, s% L }
) s- f: _: x B8 N) `}5 B5 k" m' a( m$ s
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)9 ^) _* s% q, t x' ~
public class Singleton { . E' L& n: y- l; i2 G' ]
private static Singleton instance; / x5 t, j# E5 S6 z: A; j& x
2 p, _9 T" d0 U7 k7 } private Singleton (){} r% b0 @/ `2 ]4 R# b. J/ t) L
2 Q$ Q" n! i: b6 N
public static synchronized Singleton getInstance() { 9 n# {( R, j6 ?5 T1 j8 L2 Y
if (instance == null) { ! a0 u6 V1 J B9 K, k. \, q
instance = new Singleton();
, Z0 p2 P$ U, @% M, e } 7 o7 i1 Z% N6 Q$ X
return instance;
3 x( R& E; Y# I4 \- v }
+ S: q) D- v3 F. w# F}# Z2 g z4 {! J* Z6 S0 Q0 C. w6 Y
. Z4 M9 H# O. s: p2 L' m' E# K
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
) `" N# c0 i! r4 f- ]2 E4 s- S//双重校验锁
, e1 [0 _8 ~1 k( }: t3 O6 bpublic class Singleton {( m( _& x: G( Q; e( [( h
private volatile static Singleton instance;2 w m. d' Q, R/ z3 t
7 k% i6 K" [& f2 e. h, o private Singleton() {( G+ ^9 J- W1 U6 V0 \+ ~! |
a$ x( r" C, n: O4 R }
/ e5 v% L* b' F5 i# F! D; b0 H
public static Singleton getInstance() {# {9 h. S9 h$ V& O- `$ @( G
if (instance == null) {
$ |+ \. X5 F6 y, J. v/ |8 |% v b synchronized (Singleton.class) {
4 c: s5 q% T' A$ D+ l! K3 z if (instance == null) {
8 u) ~* v) N2 k2 Q instance = new Singleton();' E/ T. \& A. u6 v
}
* P& A A7 q# \- E; u }" ?* i4 y! k7 t6 ^" B
}2 d9 r* D9 E& f8 k8 j
return instance;
, [8 W$ y6 R3 P$ L; B/ Q" H6 s: k! ?- D }
* \7 S: F$ \. z( E}
* k" ~* A: t$ f; g# s0 I5 `1 Q/ K& H# f5 a7 M% q
/ T# i9 a: D# K! c" N! U, g4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 . j0 Y `2 h$ j& p6 E& G
//饿汉式
+ | d$ h* r* U/ @9 b- Spublic class Singleton {5 [# F+ [4 h! H t9 ^# A# h
private static Singleton instance = new Singleton();
" K# D9 R7 E+ y0 A
8 z0 D$ x" y+ W; k3 M) w' C2 M private Singleton() {
/ q1 P! H2 N/ S6 M
) O+ _2 @* `/ v% I \9 T }
' E. w0 s- t* @( r2 t; p# j/ }. ^( b, k6 R
public static Singleton getInstance() {
3 \: j5 k! s) r return instance;) L8 a1 P. C$ |
}
" Y7 V5 e* S0 @& t" i}
; f# W( M7 f; O! E! @/ E
& [, _% Z1 N: x3 j1 a1 Q
5 u- h0 \* Y' _' u; F" j5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类; U9 _" @" V* N$ X, @" q
public class Singleton {9 M% e7 u) R6 r% F; I1 e
private static class SingletonHolder {. t. g, ~4 G) Z8 c
private static final Singleton INSTANCE = new Singleton();
* b+ W, p& H3 r+ e! C' o }+ e& d# t( P$ i# c8 p; x& Y2 a$ e* G
% \$ l9 w4 A' R3 c, E/ L
private Singleton() {! g1 I/ A7 x: C' ^: x( J2 b
' F5 ~ H! ~" G" M }# o( X3 t, B& W; @- l
$ I+ |1 B$ Y8 X, {& o6 F
public static final Singleton getInstance() {
: i& n+ e& S1 w% ~. V% F return SingletonHolder.INSTANCE;
. v; K' y/ [/ i' I# y5 K/ I }
2 }) J- c7 {, k0 ^2 E) q; z9 }}
?) b' {8 O9 K% T* G2 G
2 j% b0 u- i) f$ A/ {* z' o1 q( E6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 ' n' e0 b+ }" n }) r
//枚举
3 D: A+ ?+ j3 gpublic enum Singleton {
: k* D1 a- M1 [% F6 ^! i& b$ p INSTANCE;$ z( t3 I- n# Y( n: j
! S6 @) X3 S7 x. g$ {( i0 | ^ public void whateverMethod() {
4 e; f1 t. _. X f1 O+ L; D, K; f4 O8 T8 z2 h
}
& l3 z7 ~7 t- Q& c6 V" \& e}) x: D' ]& Y% G8 F8 z
4 a) ^5 | j4 a6 b4 \
8 G7 @' T7 ]& e* |6 |' q. \
总结) C' c# c6 V4 D
3 ~$ ^% B3 `) F一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
2 i3 p0 L k: q8 KPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
0 J# }' t% G" W0 D9 Y% o' w* C* c9 ^————————————————7 ?2 d# V/ u6 C3 U) G! x
1 D9 Y6 d- b: z+ f! g
) p6 E% |6 t& e: Z9 ^9 K: g' e+ \
" a+ `" n J5 D3 v
, k8 Q! h) W5 E8 k7 X4 x
; r' T5 Y3 {1 p/ k2 Z
1 e% f" m* E$ T2 y
2 p8 i1 v) n# y; D( }( a6 R5 d" i4 C, F8 Q4 Z: |8 e
原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764* F! R! L% e1 s+ O
; `' t* \- Z1 j' W6 K+ K1 L, R/ k5 I) B9 B
|