浅谈单例模式的实现方式
6 `, v! r9 Q. H2 e3 @+ f9 w单例模式(来自菜鸟教程)
7 T: q: Z2 q- z5 ?% i& P
! G" b: R* }( _单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。! d$ s0 m: t1 E
单例模式的要求
) N6 _* _7 x o- M( z1 J& D' s9 u1 ? |' i4 N
构造方法必须私有化(确保只有自己能创建)
7 P: [* S! q. X. X. X7 z以静态方法返回实例(外界不能通过new来获取到对象). R) K1 H7 z# v0 i1 w- C
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
( d; z' o2 y* L* l4 P2 ?3 E单例模式的实现
( f6 p1 ^+ j) k* ^. f& z9 A# w4 p4 p: c* \4 z. Q
1、懒汉式(线程不安全)% w* F6 p* m- `( C* J
, N2 \) x- H# s7 ]9 l) d* h% M4 ]
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
- Z) O5 ~9 E- p0 ~//懒汉式(线程不安全)
; r$ c i* R4 `: A2 ?public class Singleton { ) S( Y* i- C5 t; j$ N
private static Singleton instance; ) I/ q0 U7 L! ?
& W; D& O6 Y+ r4 R$ Y+ Q
private Singleton (){} - v( [( F% M' g5 ^) L
$ Y: H7 c$ a9 n public static Singleton getInstance() { 1 g6 _7 i# e1 D
if (instance == null) {
5 T% a6 G7 c; Q% z instance = new Singleton();
. ^6 o d W: y \; i, J7 O- j9 \) V } * V! [! X% p; u9 R G; z
return instance;
. H0 U! p4 K% M: }; p- ^# T, A' w" H' m5 \ } ' g% H! ^; e5 @, X2 C
}: i: p& k7 N8 h" G
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
M; s0 J: F O8 @! upublic class Singleton {
- ?( c/ P: c: }( M! g private static Singleton instance;
6 H; i, d% p* x8 I* G! u! A8 K g9 Q$ ?2 l% B
private Singleton (){}
# C2 e, X) {3 r3 D4 {
/ o" ?- p5 f# L public static synchronized Singleton getInstance() { - G3 P0 {' m) Y$ V4 L& e* K; G
if (instance == null) { 5 U& p7 o- |5 j5 D
instance = new Singleton(); - ~2 Q" v0 P1 E$ ^% X- |0 a
}
. n" o/ \3 B% m& W7 S return instance; 2 P( E* A2 t9 e: y3 r, h* H
}
1 u: F: p. g) T5 Z}; X) b1 p( M6 c% _
5 s* A" P1 n8 S0 }% {
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
! K' g6 y( F6 F. S6 N//双重校验锁
: @ }( v: B* H8 ]' N% f% P3 L+ Ppublic class Singleton {
2 ^3 w' C9 b7 n) K$ U. ~8 U. k0 E& Z private volatile static Singleton instance;
h- g3 n4 r# E/ D0 V$ [& p& g3 X" N9 t4 l) x" Q
private Singleton() {! W. F- r1 g- w; \: t2 a: L
: v4 P) g4 m: x6 |* a- x
}
* ~1 r. L$ M. S+ {7 [# Q& K Y" t5 m3 J f/ j
public static Singleton getInstance() {% e( B d# Z3 U( B* r! D
if (instance == null) {0 V! u& A2 a" h+ R! _$ H
synchronized (Singleton.class) {) e$ |4 u3 c) d. k$ \
if (instance == null) {
* j, e/ {( Z+ K- G: S, i$ J instance = new Singleton();* O& _* ~; o) {1 p# c6 x7 _
}8 q. l! K, M7 m; _1 N" u
}
3 [- @7 c, m# ?% p }$ |7 {* W i( U+ y% N" j6 X8 T
return instance;
: ^ Q4 v- Y9 {# X }
! r1 u, z$ n9 P& |9 V% n4 z& s" v}* _3 w% ?- H" I
3 u, Y: k$ p6 w8 ~, w$ e5 G) \9 Q& @. g9 s% \
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
3 \4 d0 ~2 v1 n: Q9 T8 Z//饿汉式# H. X6 o) z" c0 `$ y) g
public class Singleton {: K, @+ D8 C4 q+ {' n# C" ^9 C. K
private static Singleton instance = new Singleton();
L1 ]9 i" \4 V9 a$ C. z+ g& Y+ j: o- G/ P+ r5 B" P
private Singleton() {
; Q8 ^7 i% b1 V, N( M* j; ~4 Z& I, \
8 L& B/ }9 a$ ` }; p, D! ]7 Q- ^6 N) _, h
+ M& `1 _3 Q" x* `! g# y
public static Singleton getInstance() {" O0 |! T3 D5 \# ?9 E& T
return instance;
) k2 ?2 p7 B9 O- x+ T) Y: O& M }
: S1 A$ Z7 p2 T6 Y/ i+ K' a7 C+ J}6 t* d- s! o0 w. K) I# G
% j* t7 s; @# m
) n! _1 V/ e8 M% A# [5 F# C5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类: ]! v; H3 n5 k2 e( K
public class Singleton {
0 F1 O6 q- x; f private static class SingletonHolder {( s- @. L+ \. R
private static final Singleton INSTANCE = new Singleton();: \5 T9 t0 K+ L% }2 c6 m; e
}! U$ W& o! _+ \( _& T4 ] a
+ G: B3 C# g( a4 s- G& B5 _
private Singleton() {
) x$ {9 z# W! s3 i/ s6 O" R0 a1 s" x" ^- `
}
! c3 `% O- g8 p" I) U$ r
$ r3 L3 j+ y6 @" d A" D public static final Singleton getInstance() {
$ ^5 w8 i" p5 v& k return SingletonHolder.INSTANCE;
$ v2 O- u% L7 G/ a }
' c$ G# `9 U1 s' Q( V+ ~) q, Q4 E+ P+ L}
: U0 B2 g* d" \0 ?: T
( J& g w9 e' P. E6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 ; T$ e, { o* S( G
//枚举
2 e9 h+ T5 |* h g+ ~; R' l" ppublic enum Singleton {1 W7 h; w; Z3 q1 g5 c
INSTANCE;2 o% G/ X' C& d! ~( V, j
6 `+ k6 ~2 r: }8 r7 @ public void whateverMethod() {; k5 C3 P8 t1 n% [ f4 U& M
: ?' s3 z% O n }
- p4 c3 w# }2 y% i5 b6 D}
# G8 m: ^( u1 s; \( r
7 z$ D& J5 L4 i% f* x5 o! d s. b* E3 Z) q
总结7 ?2 @" {7 o! ^# b7 h! l
. z S! F; }5 i
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。9 D7 m# O; x! Y8 B3 U. }! \
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~" b' v% l" f4 o- d+ y; H
————————————————1 g2 P8 l; @3 A a9 B$ g
1 W( L( O6 n7 O
/ R* P3 ` a w8 v Y+ ]; G. g
. _) \ c7 M8 d* Y
/ y5 K- b5 k6 X5 f& [
' t1 ^+ n$ D/ @' f/ z. o# s. W
! \2 h+ Z# a2 O, j& K
: E1 u" I' V# H: P1 g5 A, g- H& U4 i: @$ S
% s2 k3 J* X+ u9 z9 Q- j原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
' z3 F8 t2 C2 G% F. Z7 `; d# a* d/ v
% m4 K3 T. v1 }( Z) _, B |