浅谈单例模式的实现方式* D! G3 x1 t/ |' O
单例模式(来自菜鸟教程)- M& H+ N# l7 \4 S7 I5 w/ O
, l# V" U2 e1 B( r3 C" C- F单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
- o# g* O& c n单例模式的要求
4 ?! @# S/ |$ u: _
l/ G8 ^4 M( w% |4 l5 c, W6 ?构造方法必须私有化(确保只有自己能创建)
, R6 j( P, k+ ?4 j* T以静态方法返回实例(外界不能通过new来获取到对象)
0 _# B$ @, Q2 c! x: P( _确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)# b! l* o3 K! w
单例模式的实现5 m* z/ H3 t! u6 U
. @5 w! u3 p! s, v! I
1、懒汉式(线程不安全)) z8 \& x& d+ X/ ~. l4 d
8 W5 n9 M# B8 w* h描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
" L% B5 `( ?$ ^//懒汉式(线程不安全)
: B1 |3 S- Z+ H, E& D$ Ppublic class Singleton { " m8 d" Y. j4 L/ F3 l* @
private static Singleton instance; 9 C8 @) n. z) i
7 {% p% o0 k2 }. N- [ private Singleton (){} / o, R: \/ I! i$ G
* L: G @1 k( w0 O
public static Singleton getInstance() { / r! d! c, { G& d2 R
if (instance == null) {
' N- Y; k& U; m0 \/ M1 b7 r instance = new Singleton();
1 q* w: J' Q% u }
9 v$ ?- v: p0 E- _ return instance;
: R9 \9 }3 j# S: g/ @, p } % J l6 O1 [6 x7 Q8 C( @8 x6 b
}
) [& A+ j4 E2 f" {# [5 I2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
6 f5 n3 B) D) wpublic class Singleton {
2 t" E% u9 H" m$ ~ private static Singleton instance;
6 V0 F4 G( ~4 S& X. {; \& E! t2 X/ \
private Singleton (){}
6 x6 m7 G, x: _% c
. K# W. Y2 a5 I N; ~ public static synchronized Singleton getInstance() { , j! n# h- m' Q2 |6 ^' f
if (instance == null) { 9 E8 `, f0 G6 I0 e! K
instance = new Singleton();
7 [0 \% c' T/ D: q$ b } 7 @/ A$ {, x3 R$ R: G6 y' `/ d
return instance; 2 J- D6 J S# [2 p
} 8 L( u' a5 _% T% b) _# K
}
0 i3 r e! g) i$ e2 i! v$ e6 A" O( |" W" C) j9 o
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 , o; S$ V) l+ }4 q2 c: o- y2 [
//双重校验锁
6 m6 i$ E" S6 E! P" ?public class Singleton {
( V ?* a9 v3 }$ A1 X& b. u: @ private volatile static Singleton instance;! j) U7 `# [; K- s, w: z
c, J2 x0 V8 R- i! N4 C
private Singleton() {
2 U" R, q4 y6 q! p& X6 R
& \! s5 P5 v. o: k; w% ? }$ P# D% _9 q- n
' E1 _" W, `8 V% u( T3 n [2 w6 W9 q
public static Singleton getInstance() {
2 D" H+ m! X9 ]7 d1 s if (instance == null) {
/ A9 z) |% r* _3 Z4 y8 J: O synchronized (Singleton.class) {
- L4 _! V6 C, @/ f- Z. `9 Z if (instance == null) {8 F I9 T/ U3 O* r8 S
instance = new Singleton();
. k5 F$ h+ j: r) x( a# m3 Z7 p }& T3 k7 U9 b: T6 Y
}/ q8 x& n& } { I5 i
}
" c7 u' q0 W/ S1 ~& C7 u. w return instance;
0 e7 D3 s8 D! w }
4 ~8 b/ ^0 y: Z& n" M# s}4 K) i# |+ ]5 I2 }8 \$ U: Y
; _( T" X& u4 c5 q7 ~$ a" ^5 P5 p$ i# T% J( j0 O8 _; B! ?" @ ~9 W* d
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 : p% ^2 \% o5 J5 x" q# Z4 { l
//饿汉式
3 z" J' J$ @% x; ~# U, H4 Xpublic class Singleton {
' O. ]% T Z% L, e private static Singleton instance = new Singleton();$ A1 _! z$ V( {- C+ t
4 X3 ?; P3 v1 _. E7 A: y: N
private Singleton() {3 t u5 _% z C+ F
% m0 l3 k( h" Z" {6 B, r6 |. X' L } ]/ ]7 k. p, x0 U
% d0 @ J g& Z3 k" W public static Singleton getInstance() {' Q1 l' M7 i$ P( q: T
return instance;
7 Z* Z) g# `7 v, R6 T! h9 i }
- [4 j* x+ P) _6 t% D: N6 `}
* O1 Z3 ]0 }$ |3 y( S3 z; ]" U" t; Y/ l+ H' D
( w( O7 M5 o0 f) q0 K6 @0 K
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类! }+ b0 X- G( v6 b3 B
public class Singleton {' h6 j) U& x9 R, Z+ |
private static class SingletonHolder {" E" _7 Z9 l% ~: `! B- ]$ t5 Y: c
private static final Singleton INSTANCE = new Singleton();6 m2 ^. Z1 U0 B, F( C- x
}4 _5 u% P; I, R) ?1 k) \0 o
6 z7 A3 G3 e1 T0 n
private Singleton() {8 z3 d4 P% p- D1 q0 C' J" E- \/ R
$ l% T$ |# i; z- R* L }
M$ [3 F1 [, y; O: l5 h7 x
/ }' J o x, r0 ~/ F( w( b public static final Singleton getInstance() {
4 S8 m; P7 M- y% ]8 q! l return SingletonHolder.INSTANCE;
8 O* d( Q* a4 s% C/ J" b }
; s. l1 I$ K* d}
( _$ H" i: f ]2 r; H! d) ?( @! T/ {$ @8 r2 ?! K* F
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
5 h1 j! Z( O. s//枚举
: i# Y- H/ O9 M! h" Apublic enum Singleton {2 T/ `* d7 B9 v2 L! J
INSTANCE;
+ Z/ W1 Z* K8 D, j3 L
% c4 S! S7 x$ C0 p7 I8 Q public void whateverMethod() {
. m, J0 A, c( s* r `% l. g. U/ a2 s
}5 C; S+ d5 V/ T4 J+ e/ R2 Q
}
, \9 ?& Z5 N& {& Y% q+ K( f* ^0 s6 Q6 t7 E( t$ a/ ~
0 p4 }& G3 w# B# O# _; y1 C总结
, `2 H+ p; a* e4 ^- b
& m& g" i- l( |0 }一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
% }0 [7 K) _+ I, @/ U9 V, q3 ^6 ePS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
4 Q+ m [& s$ c5 I0 z& A+ B/ J————————————————
9 S! N. {: V, r* `2 s
, n/ }3 m. r7 u+ ` n1 Q n) W; y6 v; T+ c, t2 v/ W
+ _- Y" ^ U+ ~0 k8 p$ r7 i) `: `) s' c" @
$ i/ q* i/ w, M$ O& m
" W- D0 L( s# E" G; B% E0 n5 h, a
, b. ~* r7 g9 @' j! E
% D% h. Z* ~3 c* ^4 x {; U0 m
. i$ ], Z9 j! x; ^: h/ G5 {原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
" i* g6 C" J+ P) _
6 g; n& f H# D5 e% }. `0 l# s+ r9 A0 n
|