浅谈单例模式的实现方式
5 ~- O) ?2 y u. B. g单例模式(来自菜鸟教程)
/ F5 K) F- x& s+ Y+ T4 i3 m- m! O4 H1 f3 g9 `8 }8 s, Z+ Y, }
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。, E4 G0 K# C, Q# y1 u
单例模式的要求
- D5 I! p6 R1 i
2 ~6 {6 }: j/ @构造方法必须私有化(确保只有自己能创建)6 d; S- Y0 U8 n& t$ F2 e2 T8 `
以静态方法返回实例(外界不能通过new来获取到对象)
. {9 I& Q: r4 K确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)* L) ]3 R7 |9 a# a
单例模式的实现( ^! m% N) c! O5 ^
# M- Q8 W4 u" H, K% ^
1、懒汉式(线程不安全)4 d7 ^, X% r# b2 e- w! d) y" L0 D
7 m+ Q0 m) X2 o3 S1 s* J+ Y4 s) j2 b描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作+ ?: E9 r: u% c7 x' \% V. Q+ `
//懒汉式(线程不安全)
& U( b& t- A$ R7 B# B; _9 zpublic class Singleton { * Y) D5 G8 k+ C, j1 A- d& Y3 a
private static Singleton instance;
: E. G" V/ J! U3 U& ]4 r, ]- L5 F
private Singleton (){} ! U& @ `2 q2 K) f7 s. ?
0 m; Q" c# {: H$ n J
public static Singleton getInstance() { : {8 \9 U" d. r3 j0 b/ d u
if (instance == null) {
4 \* ?# A- V4 L1 H% i% A instance = new Singleton();
3 i0 Q7 e: i+ P$ w1 @( m2 ^4 W }
; G. I/ h3 |" g7 [ return instance; 3 K! y0 u% g1 C
} $ o+ x" _# Z" V$ v
}- q2 o* T/ o, \' L- v
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)* R. s& P6 U& x: U: i0 k8 H# b! S$ `
public class Singleton {
% d# i/ i8 l+ O, ~$ z6 B private static Singleton instance;
+ k, F3 A& l0 }, M+ J4 a: S" T T' r4 k
private Singleton (){} 5 q, v/ u$ t) N2 w4 `+ i( x
+ ]5 N7 Y3 l3 Y: g9 t+ Z& }& I* P
public static synchronized Singleton getInstance() { 1 d* e* O7 S K' s* z
if (instance == null) {
' B; D9 Z7 ^! ?+ ?9 q0 z% P! r instance = new Singleton();
0 M7 B) ?, r( \9 H4 @ }
. _- a: z2 Q4 b/ K& g+ M return instance;
3 ]) t+ b V+ n ~9 u }
$ A6 P P5 M" [- b' n4 a( i# D}
7 ~* R3 Q& _' z5 w8 t
' X" m& s* f3 G0 J3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 M5 _4 T4 L, y7 X7 }
//双重校验锁; Y) A+ S3 L1 U0 E+ F6 C$ }: }
public class Singleton {
( H0 X7 ?& o% D6 @) o private volatile static Singleton instance;
" e1 U3 Y5 Z) j% h9 f, O0 r5 e' v$ C7 ?: ?0 S6 ^' \
private Singleton() {
$ N) z5 r" K- _" z# c. U; f# A: r' y1 W5 f
}' ` U5 V! t: Y) G
; {7 G$ k& h9 e public static Singleton getInstance() {2 i( @5 ^" a" w1 s1 }* ^) {
if (instance == null) {6 {+ f9 S! R4 g6 @9 T0 f; E3 M
synchronized (Singleton.class) {
1 E: y8 V$ \. e4 b, S8 p/ _8 m if (instance == null) {3 n, c4 U3 C) z7 P7 \) r. F8 [
instance = new Singleton();
/ X8 o3 k. L/ P, a }
' X( B+ D- x$ [! r3 Q4 p0 R }
) C8 k8 j1 B. K2 I }
* f! E& f+ q* G: F! a% I return instance;: M5 a! p6 q9 p* `4 }' _/ @4 i
}$ P4 `" s H1 V( f+ A9 Y& J5 k
}
6 `1 ^8 J1 e ^+ \0 X* z; P" z0 k, F
* I* T# s( }& |2 f( G& W9 ~
" u; f9 J- o; b+ R8 V0 \8 d W4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 / h7 [* u% y) Z* d* ]5 _ f
//饿汉式
4 l7 h$ |1 c' B2 ]# wpublic class Singleton {1 K6 k# V' A8 u% N$ D, r; I
private static Singleton instance = new Singleton();
3 W9 [+ K* R% H, G% @ Y# H% n- v2 D! `% |( q. N; T
private Singleton() {
" U2 _7 n% U( ?- V# z( j+ o: H* C6 A8 `4 m! E0 `+ T: s- L( P
}
6 }- H1 r$ Y9 D; q4 z9 G( P( ~9 P
public static Singleton getInstance() {& P, n: [6 `; w. u0 Z+ F- e1 |
return instance;
2 g8 z7 y+ o# |0 I' k }
h- Q- O0 u+ t}& ]% y* x8 q" T2 K, K1 [
; R, P; V9 V: {6 B. ~ C0 [& S8 J& }: b
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类$ g' v# d$ u0 d( }0 u8 _7 g
public class Singleton {8 \! _+ V( n# M. ^
private static class SingletonHolder {9 h) F0 _) }; E
private static final Singleton INSTANCE = new Singleton();
3 r% p% o8 k: a& E }2 z) V+ w' i: \/ ~) p a
9 x8 i. p7 k( Q" ^0 x) O2 D5 K private Singleton() {
% e7 z/ }- U$ {3 k3 \
: }5 q: [; w3 ? }
: e! a f x# L M. h& }, h
4 y$ M9 l2 s U" q public static final Singleton getInstance() {9 }5 r- }% _# V y! k9 f+ F4 @. h
return SingletonHolder.INSTANCE;
3 y. `* q) k& R$ @- X: i }
0 k+ P6 `% B& r% h}
6 A; v, Y1 }# v8 K( C# m' Z' E6 R: Y* H) |
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
6 Z+ O% `' F& g" w//枚举
1 g6 U4 o& o3 D3 A4 [& |2 C# }$ Jpublic enum Singleton {' _: @1 p5 d; i
INSTANCE;+ M7 P) c# Q+ k) N+ ~! _5 W
. G3 y, }0 h. j3 q z3 Y; q' ]
public void whateverMethod() {
+ p; E4 j9 B& H- ^( R2 Y
! I: P* t5 b+ q/ S- m; ~ }0 t1 c! ?& l1 S; ? F2 s5 S
}9 F0 T V' s8 r2 J5 o _
- Z; v. g' D! H, F( L
9 D# T+ l, \! D* V. ]9 z总结& h5 P5 Q8 q9 q$ r; V
& a6 j: H0 W5 @5 x5 O' e5 o* m
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。( b D$ q3 N- I4 A9 R4 F7 h
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
* O( ]$ h# B. H/ }7 R$ j3 I' k———————————————— B& M, Z A. D/ R9 I& G
" ^1 `! i$ D& x' }/ Y
; `3 ]" k5 q3 X8 I8 |; Q5 ~& Z; F* Z7 Q7 x! n' x' O7 j7 E! c5 J
L' t$ L/ N6 M4 A6 q7 O4 o; a# u. H/ `# \# K" ^# c
! t& |3 b' z" Y# i0 R
+ Q/ |0 ^# D1 t9 T& F' t _
' A2 i- k% j* u3 H- @( l
9 G! p( x" j$ v% L$ V( _5 p( s" F原文链接:https://blog.csdn.net/weixin_37686415/article/details/1051647640 T; Y$ j; m" F4 |. J5 G
; T. D- U5 \. ~, }" O. D, @- U' U
9 K$ T- V8 @( x& x8 ]/ i
|