浅谈单例模式的实现方式2 N6 V$ M1 Y" E
单例模式(来自菜鸟教程). p7 L3 U4 R+ A: Z
* p, K7 ]+ d$ Y+ q6 {3 o
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
/ y) E# }% C2 a( Z/ t单例模式的要求& R, O+ { p; T) N: G; k0 j
' i1 W) e, h2 E) c( i构造方法必须私有化(确保只有自己能创建)
+ g w- |6 d% D3 N: M以静态方法返回实例(外界不能通过new来获取到对象)
8 K0 t; W/ ]$ [1 [3 g/ T确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
7 M6 m# f$ y: i' ` _: _9 T+ u) ]单例模式的实现
( B* M2 O: B7 P8 d' D* A) O# }' o; Q+ S+ X
1、懒汉式(线程不安全)% {& |9 E& T) j' ~% K2 S; E
* l# \1 ^9 h) I! o- ^6 [) ?描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作; j+ k$ K4 K9 f4 T& S
//懒汉式(线程不安全)9 g9 x# K+ S# t! r. E8 M; @8 W9 P
public class Singleton {
0 ^3 v) k+ V0 p& V* b1 J/ c private static Singleton instance;
8 C- T! O9 \: P$ I1 t
5 U5 C4 W/ h& F: L private Singleton (){} ! u2 Y) j9 ~; y* _
) V( S1 \5 u. z. o& X0 _3 p0 }0 C
public static Singleton getInstance() {
7 |/ a6 ^1 B, w: I- z if (instance == null) {
' t, D9 l4 Y; {& m9 z& _ instance = new Singleton();
+ Y1 R5 {/ r X+ r }
5 p6 { d" P& b e/ o return instance;
" g2 l8 G( T: n( t* D } * ^/ M3 f8 i h* ?6 g( ]1 I9 t6 R
}7 @! Z! f* o# ?
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
1 y6 U) p$ j& gpublic class Singleton { $ M6 l; J t" }9 a* a" h$ T+ I; t7 N
private static Singleton instance;
- ]" ]& i7 b6 N, z7 C5 x5 k% y2 R$ x
private Singleton (){}
3 T5 q q- k3 Q: T) O) j s4 u
0 w7 a8 k" ` t: O. a0 s. f public static synchronized Singleton getInstance() { ) b9 U5 g$ {8 z* D$ U: c5 H
if (instance == null) {
( ~) l9 g/ h- l# } instance = new Singleton(); / k1 c0 J) ?; L" C% e9 o
} & K C' @, u* e' C; M3 R
return instance;
6 ?( e" c3 U1 n0 X4 p/ o" Q }
* [0 w/ r+ k. q! o% W}+ l: L9 h, Z/ _0 O# p
* D" E. ]; e+ S. g! y, `& H- M3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 7 A ?. t+ j" [; T+ F- m- Y
//双重校验锁
5 S5 w1 j' i$ u( i0 g5 g! v$ Qpublic class Singleton {
/ x9 |0 I ]+ r9 k4 @, v7 M% [ private volatile static Singleton instance;
1 f. M4 t, f8 P/ H2 N, D+ b6 [) }! P& {
private Singleton() {
( W+ x5 _* `' q( N/ z& D
4 T" ]- X; b+ a5 _ }
$ g" a* I ]! K: G7 I5 ^7 R& l+ x- u6 g7 c+ W9 Y3 V" ?
public static Singleton getInstance() {
. v$ U3 c3 s) f' A- Q S! E7 | if (instance == null) {
: [; Q% E6 ~ S- D synchronized (Singleton.class) {( Y; A( ~7 n2 i8 f ~1 W
if (instance == null) {
3 H2 B& k" h9 m. D/ b instance = new Singleton();# i& u. ]* b9 P% o! m2 H) u
}
6 z0 B# O* H" O8 C1 h% N. g } _9 I% ?! ^5 D1 ?2 U+ q
}
4 [5 ^$ d( P- `* S8 g4 a! A return instance;+ r& l! q. l" b" C) Y) W; m! m
}
5 Q" a2 ?& A7 q! e0 W3 ?9 x% {}
3 L C* i; I6 c, F) h2 G
! ?" O8 ]& B- K0 v6 k
. X0 I8 T' J- C4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
; c8 G, m6 N2 `! G& L& j3 E//饿汉式
' G( x& }: k" b% qpublic class Singleton {7 b3 u+ {2 d. O; H" R* I4 V
private static Singleton instance = new Singleton();: M9 Q4 l( K Z' \! {; n( }
% Z; b! Y- R! F" n% r private Singleton() {8 [1 {$ P, h! S7 G
; q _. n, W( V/ I, @
}
$ E+ p& |9 f: m- F; ^ [# H O* h) b0 @) g1 D9 \; d1 X0 k0 r9 ]1 w9 y
public static Singleton getInstance() {
9 Z) e! d( m/ ]% U' @ return instance;+ r2 J0 V. _9 ^; h. h/ | M; E
}
8 n" b. n- g2 R& {}
7 |7 I# p1 A+ d7 K7 N
3 \2 h4 p8 @! f: U0 A
1 e+ k- r4 b& R8 y9 l/ ~$ A5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
K8 i0 g) G% Gpublic class Singleton {
* z" G& m6 q4 Y! w m4 b private static class SingletonHolder {
5 E5 t3 B5 m; \ private static final Singleton INSTANCE = new Singleton();8 e7 W3 c, T, H. I% P3 F8 g
}
9 B5 v' O& G( q4 w8 Y& |' c
+ s- Z9 {# V: V2 Q- ~8 W* X private Singleton() {
& S. M7 V, }: f4 @9 r
3 r* A) \. c7 S }# l. q5 C+ o* Z, \
, m6 L" ?" T t7 G5 y' g2 @& u& n: Y public static final Singleton getInstance() {* j# U: k, F2 v, K3 I! i( \- t
return SingletonHolder.INSTANCE;
7 \6 ?, N# w% U, S }5 p# H: J9 q4 W) I; q5 S% w
}
! O" h- r h) \" G' E Y' q8 m6 m3 X8 c+ S$ L
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 6 o3 _" k$ X( ^/ a2 [ G5 K8 {
//枚举
5 u$ T% L6 W( x6 Wpublic enum Singleton {1 N# e. o2 z9 l( l7 M2 H/ M5 S
INSTANCE;
7 V+ u' H2 Q0 u% w. P: t- T' W
$ f0 ?3 N0 v p public void whateverMethod() {
. l& }' p9 D4 j0 K, e+ L$ }& [1 F8 N* c
}
@% }# R% w' S& s' L# ^" ]7 Z# w}8 q1 ~( {# Z& |! w. r" \7 A
: y, i: b3 m% p# y/ P/ f2 W
* `' {% c j9 T; e+ i* r总结* ]) _' `4 C, R8 z1 p8 U$ F
! ?) G% s! U1 {: P. s6 W
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。: U1 ~/ h7 D. `4 R. l
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
, u2 q" ^0 ~! A& q1 N3 [) y! C————————————————
. t9 j( V$ U; S7 I+ s( ^) u" A
4 A9 u4 e: v! Q/ s1 G& K9 Z# G/ @" f% {3 i
- X/ U) s4 U6 E# I% w
! ~7 I; \" q. \! G3 e
# ~" I( B# [4 O, A' R
: q$ o* w6 p( N4 Q/ r) E) l* N9 x* q' l2 H
7 |! d3 B- C; M: L6 W1 u) f
H# n9 j9 M1 q- ^+ @$ P2 Q" t: X
原文链接:https://blog.csdn.net/weixin_37686415/article/details/1051647641 I, `) r4 [+ q- n, ]* ^/ I
4 _6 F6 O1 w$ N( m) T1 o1 k* f: b7 k1 x) ~; G; D
|