浅谈单例模式的实现方式 ?- @5 B. P* i" O" k5 q# o% M$ {2 Q- Z
单例模式(来自菜鸟教程)
" }1 M. ]3 Z L0 I M6 r/ x1 [
" G3 }8 ^( D: W4 ~% w单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。% } o7 B6 A; G9 s" O0 S; X
单例模式的要求
% Q; o, h8 U& W/ g
( c0 t9 A5 {! f! ?' X$ s构造方法必须私有化(确保只有自己能创建)
1 h, c6 `7 C( i" Y以静态方法返回实例(外界不能通过new来获取到对象)
# |7 r, N; t4 ~+ d D# Z2 P1 f; S确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
6 _8 p( e+ A* k O7 k9 |/ {- U1 c) _. k单例模式的实现" V" w9 S( Z. }4 U$ x- u
t$ _* G: k( G: R$ B5 {) y8 Z1、懒汉式(线程不安全): E, y z: y H& r* T' A
, M( v' ^) u8 _- h7 ?$ {. }描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作2 X3 h6 X. p1 N& S; B/ Z) r0 T2 G
//懒汉式(线程不安全)
8 d. I* Y1 S! L! I7 E* dpublic class Singleton { : }. f+ L& T$ Z( K' b; [/ D
private static Singleton instance; - Z/ l3 x9 e& o- O! F6 e7 G/ u+ B
' V( z0 G5 I: Q2 D1 c# L. v4 N private Singleton (){}
% E3 Y, L/ a1 k: S( S" t2 e4 T9 c
?# _% J# e. _9 U, [ public static Singleton getInstance() { + e. K8 S8 p2 f9 J$ A0 j
if (instance == null) {
& ~4 j. R: ?* O+ U z instance = new Singleton(); , k# K2 n; v* \/ P9 M
} # S* Y3 ~0 s& o2 d1 y; Y
return instance;
2 W+ r C; x _/ S }
/ w) _& U4 `& F5 ?& {7 \+ D) P}
0 k$ Q0 {6 S1 @ G2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
* A z+ W8 W8 y7 y, H9 J. k) _public class Singleton {
+ }+ Y4 Y7 F$ W' i% h private static Singleton instance; 8 d0 v0 T" |$ o0 O" `" Y
. e' I8 j; @! D$ Z } private Singleton (){}
, Y9 H# u7 U$ Q$ [
3 H- ^' Z) y' @9 Y3 S: a public static synchronized Singleton getInstance() {
+ D$ |6 Y/ d( x5 }1 r4 t* h) r if (instance == null) {
) o' H$ w+ q- w" D1 j instance = new Singleton();
6 k% {: J: c: c6 q1 X3 r }
! F6 ?" w. t! I% v, y return instance;
% W |0 s4 Z1 n5 k% j h% C } + E n7 ~+ A: v+ M/ i
}
: L. ?$ }( H' q: @
3 h7 V9 A( Z% M' \# P* k: q7 i; j3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
, O4 g% Y/ I8 O( `0 P9 l/ k& z//双重校验锁0 h$ |9 W% o) d, T0 a
public class Singleton {1 q0 ^) r5 a- b$ t, ?& b# ] k
private volatile static Singleton instance;8 Z) s) H, ?/ |% s2 d
. O3 [1 I4 i4 ?; Z) A: |6 l
private Singleton() {
& e4 |0 ^7 P. h: J7 p) ]- x2 j" q8 a+ e0 {
}4 u, Z! \7 w& j: z. e- k0 X
/ n6 ]2 m2 M% _8 N4 v
public static Singleton getInstance() {$ U3 q+ J3 f+ K1 r
if (instance == null) {
3 S0 x/ q1 |. r6 N) `/ A4 @4 T( N3 B synchronized (Singleton.class) {6 u% @2 T9 B6 k. u
if (instance == null) {" ~7 }- A$ |2 U c- ~
instance = new Singleton();
1 \) i6 R4 e3 {, f% y }
& w0 u) s. R: r9 F: i }9 R3 j/ F1 ^! [
}
# `; S% D8 O! B/ M+ b return instance;
2 b6 p. l1 C* l* c }8 E: w' p9 i" |" I2 G2 q' n; v: E, `
}6 ^0 y+ P) h3 i' x: V, g. Y8 v
3 K ^8 {2 `5 V% @. h( V: A
1 Y5 F: A* u! t' M
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 ! H+ @+ D( F( f8 o! F! f
//饿汉式( x( j5 g3 ~, z" U, H
public class Singleton {6 ]' V/ Z# P* c8 X8 @, S6 O. @
private static Singleton instance = new Singleton();
: X& E- Q' e+ A/ h4 e) c
% b) \$ _5 M1 y' ] o; A* l9 L private Singleton() {6 X$ m6 X6 ?+ g9 l2 ^4 r
3 S8 m* N8 z D6 A }, t- W( y' l: S% K) ]
/ k) J$ N% C% k/ u% F7 ?. c) w public static Singleton getInstance() {9 {3 S# k0 {& D/ q
return instance;
2 @% U2 e% M" F0 m, H) G }
% p- Y {, T$ J}3 u1 F+ ?, Z: }% e
6 l* ?, \* x6 Y$ L! z$ i) @0 z0 J
7 Z" N: J8 J7 O5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
% v2 Q- @$ q" H$ Jpublic class Singleton {
( d2 @ ?- p9 I. W: D* x private static class SingletonHolder {
1 x4 }5 @9 ~6 _& N+ I private static final Singleton INSTANCE = new Singleton();
! t! u8 \/ o$ w6 ]( k1 O }8 u& C2 ^/ c# S4 |! ]* }
6 R7 _3 b4 h" U! n6 _
private Singleton() {
O* `* Z8 ?" }) G) D) V% Y: P4 V
}
0 A8 f h" c/ O, c y# [! O& s2 j( p& L/ u& v; @
public static final Singleton getInstance() {
v4 I% Y/ m( Y) h$ E return SingletonHolder.INSTANCE;
0 D; N' h# K7 X- S" V }
9 w7 E( ?& u; z. J/ ] w' o}
/ t3 V- F, N6 m0 C3 V7 u
0 Z6 g8 v( Y* j% k6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
' Y# c* V& o9 a: g" N( X5 _//枚举/ F) @3 V) P) N* }2 u3 K
public enum Singleton {
9 W( }3 _+ O( D( \9 ~9 _/ g INSTANCE;# |5 J' b6 A& S8 o
1 b: `, {! b+ m2 P3 P public void whateverMethod() {
8 a" X0 T5 f6 r: z3 N# X4 R$ Z3 G9 f9 A/ J) ~, f% I+ w+ k/ h
}
0 g; Q o4 |9 B# Z5 ]+ }}
- P, H7 g6 _, b' Z2 g. D" C0 w8 g
+ S+ U8 z: w1 }; n# U# g2 {) f, E2 a. h( d/ r
总结
; B9 y# l/ q, U8 C+ ^! ~( C, A2 e
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
9 A. U0 r* d! h) F' p6 S5 [PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
, w6 C" G i6 v! ^————————————————# [$ N/ I9 z2 ]# ^
* X! A6 N1 A; Z% ?( N8 t5 B* e- I1 W" F+ Z" R( _4 Y$ M+ O
( A( X K$ Y/ h5 Z: `, M5 [( ]
0 Z% M% H6 g. t5 r
; T9 s8 Y! V- B. r
5 f$ g! V X, D! o1 A
$ r/ U$ n9 X+ p- s9 O8 I
6 g, e! Q! @; P8 c
, Z) Q {4 V' e7 B原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
; W, W1 ~6 Z$ g/ U
8 _' O `+ U6 m1 {* w( R9 J/ u! I1 J
|