浅谈单例模式的实现方式( Z N- o# k; k3 o( c0 W
单例模式(来自菜鸟教程)0 A( c6 w4 X( N& Q% E m
0 c4 V9 c9 s* w1 L, N单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。4 f0 n U Q' ^2 B7 r. u
单例模式的要求2 X: B, S4 m+ P+ t' w
+ B Z& q) I6 a! H2 r
构造方法必须私有化(确保只有自己能创建)3 g; T0 U2 r( q
以静态方法返回实例(外界不能通过new来获取到对象)
/ z1 ~, D" X6 K! \确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
3 i0 t9 P& X. O3 i& Z单例模式的实现
- T# Z8 D; L( V) ]9 Q, s; r+ v9 {" W$ \, l6 ?2 N2 R" ]& ~
1、懒汉式(线程不安全)
5 | Z! W: J% j8 }9 Z ~6 ^* U7 y4 X# ^7 x
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作1 q) T4 P6 O& W5 u2 s, N; V! p
//懒汉式(线程不安全)$ i8 v% v0 `# `0 n
public class Singleton {
8 m9 m+ n6 v% S7 ~ private static Singleton instance;
! a" `) I1 k. `5 V# J8 f6 l, Y& H' o& Y Q5 Q$ z1 y- U; {3 |. m. ~) }
private Singleton (){}
3 L) p: J4 J7 ?' e% u. r, u- f2 O. p: B% ^( h" | F$ ~, N
public static Singleton getInstance() {
+ I( t; }1 p$ _+ t if (instance == null) { 1 L% j7 f# t) g9 A7 S. c
instance = new Singleton();
9 W4 V& L) s; J, d3 J/ j. ~) Y+ i } E+ i" n( r0 w& c4 Z0 l
return instance;
/ h% |, A3 |+ e' g1 D, H4 i0 ~; t } . S- e3 z. H8 g7 P2 f- s I2 ]
}
6 Z0 j* g4 L; g- v2 ], U6 ^: ?3 C2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
, J. E! D1 r, l4 w/ o. n$ @public class Singleton {
) M' H0 I2 b0 g$ j6 E: C$ ` private static Singleton instance;
- M& j! Y7 b7 p$ e2 ~" U" d
% i" R! b( T+ s( q8 b) {7 v private Singleton (){}
0 g* N7 R: Z8 r6 S5 S
8 v) o8 N$ h5 R3 ^- K! @ public static synchronized Singleton getInstance() {
7 S# R5 n- p# O if (instance == null) { # F3 J! k- M& d' A
instance = new Singleton(); $ p. C( c) u/ E, S; Y$ p+ S
}
4 g* r/ O. v. N( O6 ] return instance; 0 X" T' Y; A. W8 j
} 6 R# U" F6 b/ X8 o' A
}9 p1 }7 i! F& z. P
% ~0 u! K$ w% \2 I9 A9 y3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 0 T, A5 w, p& {# |. v
//双重校验锁; p. t V+ ~5 m/ ~
public class Singleton {
5 g" d8 N" ]+ x/ H! {6 v* N2 e9 ^ private volatile static Singleton instance;
& B# Z1 d% @9 T( U& X! [# y3 Q3 e7 a' r$ R9 U! V+ C2 x
private Singleton() {
* ?9 [) `& `7 M2 ?% A3 E# K' e, k4 \, z ?4 R
}
( Z# I; L5 w& |% k* ~' ^+ U. Z! Q2 j0 O! ^& ]' F. A: q" A
public static Singleton getInstance() {( o/ _# m5 M0 x, o
if (instance == null) { ?; q5 p8 A* o9 q
synchronized (Singleton.class) {- o4 E9 m. q9 ?: d X- E4 O
if (instance == null) {
9 v% T( }5 B5 K0 ?7 j instance = new Singleton();; `3 c, {. h% M
}' ?! r6 U/ r. k3 R. ?/ F/ C
}. P1 |3 m7 Q* S5 K
}
- X7 `8 W( E/ U: G/ o9 y return instance;
. q$ G: V2 K% |" r }) C0 _$ t' G9 Y5 B- Q: p9 I
}
. D+ I0 K' z) W5 @
+ G" i0 @6 @! D4 N! f/ @- P D, h6 O; h5 [/ L' Y- S
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 0 _" Z X4 F: ?! z j1 Z% s
//饿汉式
" l3 \" a8 ^5 dpublic class Singleton {
6 I) S, G2 \ ?, e private static Singleton instance = new Singleton();
4 c6 ~8 d# ^: f/ c$ J3 X& X& x1 B0 s' [
private Singleton() {
+ ~, {5 D& C) V5 }1 b4 d$ j( W O! M+ F5 {1 `1 `' C
}
' M! u" X# p0 E( s7 l c& z' s4 L3 J2 ?4 d4 n
public static Singleton getInstance() {, `& f5 G& ? l% }3 A; h* ?6 g
return instance;
" C& R9 Z5 N8 H W% ^0 v C }
. F+ e+ c* |+ E+ h: W}
3 y. G3 D0 ]' Z4 ~ a
" o; S2 y0 V! h- v3 \, l% P
}2 W% r) G: p4 n1 c4 d, i5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类, } F0 a. ~% {- F
public class Singleton {5 [. o9 Z7 k+ h$ o( t; V5 W
private static class SingletonHolder {" `* R$ }5 V' U
private static final Singleton INSTANCE = new Singleton();
& f& o# i1 Z; L+ R) d- s" @. o3 Q% [ }
: q. f, ~5 g7 r! ]& J+ _& L9 R; M# q( w$ v8 j7 V6 C
private Singleton() {. ^$ h2 Q, N5 O e$ o( I
+ Y, X" ~, {1 y4 J) [$ z }
, e- s- P M5 L9 A2 C+ V1 w2 g8 f; r$ J+ f* D. [
public static final Singleton getInstance() {# P j: A* v. ^( i
return SingletonHolder.INSTANCE;3 e8 [5 l% Y7 D" P% d; d( t& ]
}
5 M: b3 D; ~% Q/ B( m- g o}
9 h! T9 t) A# ^1 M% |- b5 `5 Y. g3 F' s% ^7 @1 H. k! j
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
: d$ T( i! M% k3 m//枚举
2 l' k! j+ \) p9 k4 ]2 f! |public enum Singleton {
) I$ Q3 P/ h! t INSTANCE;- p3 v( ^! A6 Q
7 B+ N8 i* P* }2 R+ V
public void whateverMethod() {
! u( x# k7 T S% C6 {6 {6 C: S6 f( B3 R( u/ a
}8 A2 Z6 a2 Q4 C. k7 ?( H- F0 r
}$ a5 q+ M B( Z6 F8 ?5 p& C; I
: d3 R( c- Q8 c" y j) G6 M) h; u+ j9 E, G
总结
. C$ m& y" t( x# n, C: z2 g, | N8 k9 |, i' T( K& j
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。: e$ f, |, I: M! R( @
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~. Y L3 v! f1 b# v, X# L
————————————————* e2 v- T v' H
" @. } w/ Q4 J, I" l/ l2 R
/ d: H: q4 b$ K% x. S
( z$ b" ^8 B* S2 Q. n( X+ R0 e$ Y
3 s, ?0 ]+ S: ?9 W0 s- S7 P
6 ^" y# |" ~0 W0 q
: R9 c) Y: E ~$ U0 h
4 p, M8 Z0 U: i" V$ f& a' y% x9 ~" F+ T* H
. B3 e+ y% G H/ Q
原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
2 d8 R5 m+ O6 J9 ^. p% d: z* s# I- j( M
7 K" L3 k: X# l |