浅谈单例模式的实现方式2 L$ j3 R. I W& h/ L6 |4 U. Q
单例模式(来自菜鸟教程)5 M, D/ _ Q# m% T
0 [& n1 R! u0 R: `; r! r单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
! @5 s" K0 n( y单例模式的要求
' r( C: f* \7 V0 h; ~6 k7 J( g: f+ `3 v0 O) U
构造方法必须私有化(确保只有自己能创建) a" _ K% _) }, B
以静态方法返回实例(外界不能通过new来获取到对象)
$ l; H" F3 P( ?9 a3 {0 h6 q确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)2 `/ x, i$ R9 o% k" H
单例模式的实现
: L6 x j$ G7 _- g/ }; r; b$ Z
7 {9 ~! b2 v, X8 u, B1、懒汉式(线程不安全)0 D6 Z i4 T& o5 {
* W8 v5 D: Q& H( I% z* W描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作$ R) |) A1 s D# Z# v0 V: M) A; S
//懒汉式(线程不安全)
$ S- k8 _/ b3 L) @' n! u( ]public class Singleton {
- {) V0 h; `3 ]- y' Z' e. J- J3 h private static Singleton instance; 0 v$ y6 O- _4 F( K. G0 D" z% M! P! C
8 R3 x) _( g6 ~. Y* ]! G! B
private Singleton (){}
7 }2 |8 N+ b4 Y4 a3 m% M$ c: I- n" o; t* x- ?8 J. B U
public static Singleton getInstance() {
6 D0 B, a2 L+ S4 K: h0 d1 c! m if (instance == null) { , I# K0 o/ S& z% Z
instance = new Singleton(); / A& Z# B& t/ D I9 v! Y. ]& H
} ; H7 a3 d9 S) w- Y/ F* G
return instance; " q1 o+ z9 q7 b* n( l1 |5 S9 f
}
7 Y7 l# q. a% [' v" J; e}
/ K! W f5 e+ U! b2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
6 K0 _7 h( B3 B/ i5 _public class Singleton {
: W* V/ v; R5 m6 J6 n& `! h* c! D6 F2 ?" B private static Singleton instance; 0 u# A" ? l, T7 S
# E: V6 E! q5 ~0 {! Z
private Singleton (){} 5 N/ g: `4 ]0 ^: c: F
) T7 R. j8 s( I/ J4 N% P9 o
public static synchronized Singleton getInstance() { / R) g; `$ f' |* ~. O7 w
if (instance == null) { 8 M, P4 V4 g: B+ A2 m+ _* i
instance = new Singleton(); * t: a4 e/ }% @ Q& m" o9 y! b* O- H
}
4 U! h" O+ r5 [- l return instance; ; O2 B- r% C% w8 `
} 7 }$ M% q& q6 ]6 C2 E
}
. m+ B9 P5 c5 h2 m" W, O* F8 b4 m/ o
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
L% [) P; R; ^8 Z2 f2 O//双重校验锁' i8 j$ z) C& S
public class Singleton {; F$ q* G7 {& x
private volatile static Singleton instance;
* Y J3 N+ n$ l9 _
6 C5 g, @6 h+ J( |& x8 X private Singleton() {, |9 x0 t( \& t9 q
7 ^/ ^/ b+ W' k
}* U. N$ p, A" J5 y& _
4 K: l- N% g- K b' D2 s! B9 s T public static Singleton getInstance() {( m. y, y2 O7 G3 C# ?1 { ?( |
if (instance == null) {2 l* v6 p0 g4 X8 F; S2 B
synchronized (Singleton.class) {
$ ^" ^ D2 i; q% Z6 T if (instance == null) {
5 t+ K, K/ g/ X instance = new Singleton();
% u2 ]9 \7 G4 ]: W! @ }) Z# L: `% `5 d5 v2 N
}
8 |/ h, f2 Z) @6 ?% E+ a }/ ]8 G$ j7 c) |7 e# j3 T
return instance;" i/ h6 k- L6 g/ X$ J
}
7 N5 ?; L- {% p2 a} V! n# g0 x4 p3 l) H, r7 O4 ~. K! l
! n: n* A1 e8 `
! W9 ^9 d) M K; R6 [1 _- M4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
" l6 @' U+ ^0 g& I4 e1 U% Q6 R4 a//饿汉式/ Y4 y! `( ?* M9 y: A, r# ?# q
public class Singleton {
" O. `1 J2 Y+ J private static Singleton instance = new Singleton();9 K: C8 g: i) v, A+ |
2 Q1 h8 w4 I! D( v9 E private Singleton() {8 R; K7 h3 K! V% Z( S
: v; n) ^8 h! A/ h& B
}: e( e3 j' q3 ?7 P+ L
" X' G6 e6 y* c4 y
public static Singleton getInstance() {7 l* X( U1 R: ]7 b: j
return instance;( G# j7 c: i. N- g8 v6 }
}
* h p7 R$ q! k* N9 c}
' A# Y. }- B3 D6 Y) ]/ m; G
0 G, K9 W- w7 }8 Z$ U- P
; a% j v! ?+ v4 p5 j/ q+ t5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类7 H. y) S3 A) [* D3 m$ ]
public class Singleton {6 D) E8 p ^$ z# R& O0 V. ?
private static class SingletonHolder {
) @; { O5 V7 q# G private static final Singleton INSTANCE = new Singleton();
( u$ D) [- R! B; j M$ y9 d }
* y2 @4 Q2 B7 D+ Q# |+ t* s, r1 L; d6 p; M' t8 g+ Y; T/ h* H, [
private Singleton() {$ A4 X+ z* C. U7 f' H5 @' h
# J& a3 w* Q$ f
}
' H2 E( ~9 z2 z+ r. E1 C' Z
* f! m1 s9 a( F- X6 @5 I' S( _' I: @$ K public static final Singleton getInstance() {2 T. l' v$ R( O* p6 e" Q" G3 H
return SingletonHolder.INSTANCE;
7 _: Q2 V$ I, p- j; S- F& C6 V1 X }
/ U) V! o% t2 O C, J% L}
7 c( z0 z: h: ~7 B/ }6 K
$ t t4 Z' ^; R- N" v* {6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
/ N. R, z# w) P3 W# C//枚举
% ^; L( @" K- M# D# N' xpublic enum Singleton {0 @0 J1 d( U6 T- m. W4 p
INSTANCE;
5 N; @- H1 ^, Z0 C
1 H' s2 l$ b& S2 i3 w public void whateverMethod() {( T; H' X* n2 T' i
2 h2 x2 B. A. E; Q! s }4 H% \6 U& K, h4 ~, z; R5 p
}
5 |- ^2 L6 C# k. U" b
% t4 u3 U+ z3 Y1 N* R2 }2 w; ]# x Z1 R# U. h
总结
' i/ O m! E' x# O' \5 R) P3 z+ g
+ @( a! O% h$ D8 |. G一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
4 v% J: f d" E& L5 R% J: WPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~# y! `& }2 k6 u! e, M
————————————————
5 u6 @; [; \, X! x/ D3 A* W- P9 Y3 I0 P8 o& c2 n% Z8 |- o9 N
% v' A1 t! G( l5 s/ f
" m/ `, E" I$ W2 G7 x5 Y" R# r6 G, ^
: _4 X% ~6 y# T: X; }: v2 p( @# |$ R: d; R* u: K g
. S/ Y9 k6 X2 w" [2 V
- o3 a# b2 Z& P* n
6 C8 ^; ?. N% J8 j% [! j, r) k. }* E' B6 x
原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
+ ]7 ^& R) h2 H. x& n+ k; E1 Y7 d+ m" K# A
& v: z. R" E* K8 n1 P) i8 Y, x2 ^
|