浅谈单例模式的实现方式% s( R! k5 D% a; h- A. i; \
单例模式(来自菜鸟教程)
* s7 V: e+ Y: [ ^0 P/ |- J$ f( A# T; W" U8 _ I
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。2 S; f5 E; K' ~5 W7 v' X
单例模式的要求
8 u7 s$ E2 [! A2 G* e+ N5 L
# t0 O! w) q! }* B: p& b构造方法必须私有化(确保只有自己能创建)
0 A6 ^6 X. n9 J+ V1 B以静态方法返回实例(外界不能通过new来获取到对象); u4 r. d3 Z7 U
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
) j& F3 _0 r8 G$ y+ Y* l( ^. V! H单例模式的实现) M2 _! T2 V& [! G
4 J+ l2 x, Z7 o+ U0 v0 S1、懒汉式(线程不安全)
1 I6 W# L8 j# f7 y
" f, t% `+ j2 C) l% W* C6 V描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
7 I. a/ C$ b# k- Y6 }& O//懒汉式(线程不安全)
3 i: n9 m( `. s& Mpublic class Singleton {
/ P+ o/ V5 G& y8 y, X8 n) @ private static Singleton instance; ; J2 T9 v! V) Z: q; \
. G8 U0 B2 q3 O9 c
private Singleton (){}
" o$ A* i2 t& ?: g
/ ~6 r* v7 K6 B* |0 G, q3 M public static Singleton getInstance() { " b" X, G1 G/ }0 g2 `' z
if (instance == null) {
/ }0 b6 g# A/ _- U6 a- S instance = new Singleton();
' H# F+ h- q3 ~, i( Z& N3 ]/ n }
" ^1 _2 W* f, \" c$ p) y return instance;
& r+ ], P4 P4 k }
# |0 o l0 o R4 f" c; ~}/ q3 O" e$ @: b
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
) T* w0 l& {8 r7 A+ j. cpublic class Singleton {
0 S) E2 e _7 r; |1 u private static Singleton instance;
. B( z/ ^* y; S1 }. F# b4 C5 G% [9 h/ j1 K+ O
private Singleton (){}
3 w6 ^/ k' B9 T& N3 Y
( w; W8 U( }5 s, H. g |, g public static synchronized Singleton getInstance() { : C# H- K* V- H) | W/ k
if (instance == null) {
; q! K5 o, n& r6 m7 U instance = new Singleton();
4 @1 H; _. O$ R) l }
3 Z) C: {( v0 x: f' w4 T return instance; : s( z+ a7 j" K' ~3 P5 e
} & H. \5 {6 `6 |; w! x6 n4 T9 F
}
, S4 N, t2 H" G, X; t, v; H% q7 v
- V5 q6 B/ _- `4 ?' e3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 3 x0 G; n6 w1 b+ `: D+ v$ i/ l
//双重校验锁
9 q) N! m$ n8 p8 z8 h# E/ n& `public class Singleton {! E0 u8 d3 o. F1 Q% W: C6 J
private volatile static Singleton instance;
- [- y( `& V2 F- X' y. e. N6 _+ a8 F0 \0 x
private Singleton() {1 t' K1 e N3 s- v1 \1 Q
0 z$ u) S. m: \ F! P: R8 L: ~4 { \$ j }
( l. [/ [& R1 N" w8 f& L$ u5 Q# s' i [7 B6 ` k$ u
public static Singleton getInstance() {
6 o2 M# W0 x' C: F if (instance == null) {
' P8 {3 m% t- l synchronized (Singleton.class) {3 L# W5 x2 a7 g; g1 j3 k6 j! o
if (instance == null) {' `3 E) k* n# e: I/ [- ~ t1 M4 _$ i8 o
instance = new Singleton();
, y) V* L" Z2 m, V a }
1 @! `. m& w0 Z" q v, h3 D& C: t } S5 p. _9 w* I8 A1 B( {! }; z
}
# F1 W# A3 B- a, N3 e return instance;
' H8 h$ G: ]; B0 J( @# S$ X }4 t0 Q1 G6 f/ i/ c
}
' J& Z! }$ y, K6 S
9 W9 v, q: M8 f# u0 F
7 J5 C8 N2 N" f3 D4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
/ c. N1 _0 e1 h6 @//饿汉式" m+ e3 @8 x4 T2 b H, `& x& s6 G
public class Singleton {
% `2 ?) c4 `$ X/ L private static Singleton instance = new Singleton();
$ \' G% Z7 q9 O# I) g# S0 r1 Y
5 l0 ]$ |) t5 ^0 T$ s O" R private Singleton() {& X% m5 w* d5 f& S) _5 p; K
: G7 G; L* c3 Q" z* n1 \( ~& j
}
9 m1 I% D' ^" U! R a- G- P
. D; W5 u+ g5 A8 a! ? public static Singleton getInstance() {& w; ^( `7 Q5 M7 b2 m
return instance;7 [5 l5 U d6 [8 T
}
) I6 h Z; w6 Y4 k}! ~- V. m2 x+ D; o
" y- _ p! @3 `- J* \3 p, O' L1 k: |
0 C4 p6 ?# n% q9 U, |5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
4 Q) ^/ T$ |' b- h' k: T. Opublic class Singleton {9 C2 G# W2 s J* D4 m7 s' v M
private static class SingletonHolder {4 C- Q& P4 D9 Y. s0 R+ j! F: B% e+ ~
private static final Singleton INSTANCE = new Singleton();
( b$ R5 x: F! j" i }4 O4 t3 u- f' h+ ~
- |- V3 U5 O' r9 M
private Singleton() {
) j* o: N# q6 V. B, o) M/ J# R& ]$ F
2 x1 r- _! S- v& i. a }0 y6 u, b" ^/ {$ ~& v, A' S
0 e/ ^3 V5 _; r; p0 R3 L0 W public static final Singleton getInstance() {" X* z% W/ Q5 T# C8 H( \2 l
return SingletonHolder.INSTANCE;
, E+ W/ v* ~/ y# K }+ N# _) W$ ]- J e, t6 q# X4 R
}
8 e: b+ A1 c) N' ?) K! U8 p5 n( K9 y' Q. d U+ p3 G
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
}8 K5 M: Z- G# J1 g//枚举; U1 E0 a8 a( D4 t9 J+ U$ d
public enum Singleton {* i1 S# {- Z1 ^ P6 O/ g, b
INSTANCE;$ a. f+ O9 p. }! s/ J
0 U0 a; @4 u, P( X) O1 s$ q- k public void whateverMethod() {. f. g# x1 C& E' k( k# a9 I6 h
0 a: g5 ]/ i! Z& D8 K& T }% k6 _2 g* a- y& Z$ z9 @, a
}
& u, ^: u I, u) w% A5 I. t) n9 i" Q5 F4 Q2 Q
& [8 P/ q: p( e" ~" B8 t' s
总结4 z% ~: e f+ V, \" J# v/ D
9 t& }5 ]9 m. c( S U5 b
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。& S) W3 k3 b- L; J5 [5 i6 m
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~: x7 V q+ Z/ a" o5 T
————————————————7 E, m' s( Q8 f' G" N0 f% X
: e9 `% G$ u' d2 P7 V% ]( Q
4 F+ j9 A: ^! Q! N5 T) f% v! t. ~5 U6 F; R4 [8 i
! l1 f* N" t% L! F5 d& L% p! T
3 H4 z3 Y4 e5 A' _2 l6 J4 o a
, ^, H& I+ }, m( b3 ^
5 ?% p/ }( ~; e0 O5 Z, z- b
7 o' A* {2 ]4 U* F. d& Y# y) A6 \$ [9 d
7 Z9 P# a3 o+ i1 \原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
. C' J" W7 f4 D% K' Z$ p
' @* o6 Y R5 e' i+ T6 B: a: ~& w4 j6 v0 E: l( x/ d9 Q
|