浅谈单例模式的实现方式; o2 F# H' {, O. K3 }
单例模式(来自菜鸟教程)( @( _, T+ y, v3 b( F
* `& f6 c* @4 N. W7 }$ K* C单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
' ]( y: u9 d+ j* v9 L* A单例模式的要求7 l1 i8 T2 f3 I3 |% d
; j3 L$ X, l' m5 b; K2 Z: I2 f: u; r构造方法必须私有化(确保只有自己能创建)# u4 p3 E/ e' I0 X% Q% f/ @* [
以静态方法返回实例(外界不能通过new来获取到对象)
8 W8 R+ b' `2 N! U s: }确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)' ?3 u, Y" Y2 H8 e9 ]
单例模式的实现
/ r2 x s& v% R K
/ o6 o/ C Q* L; Y( D8 S6 L4 d2 a1、懒汉式(线程不安全)
A/ A* o4 T2 S! U3 v' @2 ^. q
2 F8 l' F7 Q# j5 A0 ~8 C7 `描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
+ N7 \; T% X) K2 C/ t/ v//懒汉式(线程不安全)
( L o( ?7 }2 |+ V# K3 Z* Tpublic class Singleton { . q: s$ s% E" t3 |) z! }: E* u5 ~) ^
private static Singleton instance; * ?2 a# Y! w$ m( R! }$ B# F' u
, q! \9 L2 F- V+ z* x: D private Singleton (){} % N5 C$ m( \+ w# g) D
8 X* ^! s2 w" N+ t3 ?! | public static Singleton getInstance() { * Y9 [8 Y; l/ K; q a
if (instance == null) {
/ M/ p. n' f" p- d+ C! d instance = new Singleton(); , y7 H' T' O9 m% U- h# ]& v
} * Z1 a* V& g! Q9 O) I$ H$ ?
return instance; 5 S# ?& G+ p- U" i" x4 e' A
}
3 I# N* G0 L& E' V% O" `8 h}
6 ?2 m% X6 g) s' h2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
2 e0 U6 t/ M- mpublic class Singleton {
1 N" \& C. J1 P# w private static Singleton instance;
( G$ C# H( O' u" a, k, ~; e
6 {1 L* v# D) a8 u/ Q private Singleton (){} / w) i9 o" Q# V& n7 `0 H2 l5 _; t
8 A% G3 }$ t, v. V- U1 O
public static synchronized Singleton getInstance() { 3 y* i5 y f2 o m( v
if (instance == null) { 8 r# `2 r% R3 O( E/ t) c7 Q+ G. ^
instance = new Singleton();
- ~0 {# p4 l. e2 `2 u5 o } 5 U# e6 t4 m4 O. z
return instance; & c* P! c$ N c/ v
} ! L' M, ?* \: d7 s2 }
}; g/ v3 ?% [$ _1 \* T! q. X# v
; H+ A6 R5 u" D* h3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
' E* X$ y5 |5 _2 u//双重校验锁, X' W) N; D% v2 {( X8 D
public class Singleton {
6 x! Z7 ]8 f/ Q, u+ e0 J5 ^! H private volatile static Singleton instance;* x! D% E+ x" f; y, U
& W& ~7 Q R0 D) D, i private Singleton() {
% T% K$ R0 z q+ z& D' Y+ P. z" @% \% e
}
% f$ J# k5 l( h6 i9 D+ L! T6 f2 A; Q |
public static Singleton getInstance() {+ z7 v9 {7 }/ E6 z6 m- f" q% B
if (instance == null) {
$ _) ^8 N7 P9 P7 K synchronized (Singleton.class) { g. x8 ^8 f" |: d: F
if (instance == null) {
* H0 N8 f0 Y& ~1 B instance = new Singleton(); g$ m0 M4 r6 a1 ^
} n3 X2 a; \3 P0 G; d
}! r. g- x, I8 X7 M; } o( Z& |
}
' m7 M' s5 X9 C2 k* w& Q8 s return instance;! n# ^0 b/ p) [5 B% o
}' w/ ~2 t# j1 _* O: {* @
}
) D. I* S. v3 H9 ]; i7 ?$ C
7 U3 G# b; z" q7 J& s9 c4 s9 G
- {5 m7 a' K6 z7 x# e" `4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
. @4 K; N1 L& D//饿汉式
5 S% E: L! D! wpublic class Singleton {
o7 ]4 |, V8 i* k private static Singleton instance = new Singleton();
, f4 `5 d2 {/ O7 n+ `5 P5 L2 I6 r4 O) W7 O2 x
private Singleton() {( \' C; y/ z7 l1 l. z% N; Q
2 J& Y9 K0 V, W; D9 P! j2 R7 F }
5 X# w$ C; X& k3 q; M3 d/ N" I' |# i
public static Singleton getInstance() {
& E$ R( F5 l2 v+ k6 f4 A" Q+ O return instance;1 h5 _ Z% x: X+ W, J0 g# P
}
3 G" ~ H2 B- A' ~- K}$ ]: S+ ^$ ~/ i( L' ]
, M# w* q/ V1 y: R+ I4 T6 q
' H' @ q4 p. l4 H1 {
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
6 d2 m q1 U U5 u3 Z& Apublic class Singleton {
# S* ]5 J/ S! ~8 W9 o private static class SingletonHolder {
- b8 @: l% x% m7 ?0 v; ] L private static final Singleton INSTANCE = new Singleton();
* F* }( {; i1 W2 E" ]! A7 T }
8 @' M- x' h* ]" f* F% q- M
8 l/ X6 F$ v9 A) t private Singleton() {: y. r8 a, c% @- X
8 N8 {& Z, V @" i }
! V2 W# L# J e0 w: P* v5 F* x6 q1 b l! {2 p+ Z4 s# s! @
public static final Singleton getInstance() {
& t8 t3 q3 a) A3 s" K$ N return SingletonHolder.INSTANCE;
4 Y+ x; q! V. Y& u4 h% Q+ q0 {/ N }7 U* U" ]" [. J; _% c
}
; K0 ^" S4 b$ e5 U+ s6 O( y
4 ]( [, J, W2 Q/ O1 D- `2 I/ u6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
! F9 ^ K# b0 Z2 j//枚举/ H9 T7 g5 ?' i; r$ I; V( Y* Y8 V
public enum Singleton {
, i) E C$ N/ W2 j INSTANCE;
) D4 G w' t5 ^7 y
( v! P, o- l3 @) ] H2 b public void whateverMethod() {
- d2 @: S$ U3 K* F% \9 |0 D; Z! ]8 q+ [& E8 {+ l
}
7 _- p! J/ {# V) g# w}
) ?# C, ~& D' r0 X4 I" h# k
4 a$ d7 l/ N9 M8 W
2 E+ _) Q8 P$ e; ?总结! B) P% m9 o& G- y' j
9 E* u' m: ^& H( B* S, n/ ^0 H
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。7 b5 U# [1 h t' [
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
" }" t( V5 h1 D1 A————————————————8 Q& O8 I5 e2 _% f! R. U& ]
( @. N/ L, B& N& t( N/ }' `
# u8 r7 \* @5 `* d% O
1 D: ^* m8 o$ ]: z; E9 K# n
' g ?- z# Q# \" r: Q) i
* i2 {/ I. T5 t e2 z/ P7 C! ~6 [" L- ^& a3 d" q
, n2 c' C( d, C* f$ h; C$ O7 m5 P& B8 O ?; ?
! j. l& z0 ?4 b
原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764# Z! K, L- h$ O& _1 b
8 n( w" |: d- n4 ~# o. w4 e! \
0 L# g- a8 s" k' ?/ T: k- w |