浅谈单例模式的实现方式
$ w2 D/ A. ?, c6 f, @4 t8 [! A$ b0 w单例模式(来自菜鸟教程)! E' T3 d! J6 i
& C4 d4 D% |9 t# G单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
3 F- j( Q( b7 U单例模式的要求 w' R! H0 U/ }3 P
, }6 d5 r5 Y2 U4 g% V构造方法必须私有化(确保只有自己能创建) i& z$ n$ g0 ^3 h Z5 V$ V4 m& U) x
以静态方法返回实例(外界不能通过new来获取到对象)
( ~! ^, y( W; A: g% J A确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
! h Z5 ?; z2 Y" ~单例模式的实现
k# H3 R5 z3 a. k
" ^- h1 C0 J, _1 ~% B$ o) L/ v1、懒汉式(线程不安全)
2 a7 D2 y {- G/ ~( j! z6 w, r' ~% U) s v I
描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
. I' n E2 ]% s+ h) P/ \7 r" [//懒汉式(线程不安全)
- e! a/ q, ~- `( u1 Z- \public class Singleton { * k/ }8 X; s& _+ u8 o
private static Singleton instance; + O: p* f: a3 b. q5 d
# y0 {6 q) A9 e+ [# h9 ~ private Singleton (){} - {6 ]. T4 s0 G- F8 r5 |
. C% [ o2 t+ l4 D6 J
public static Singleton getInstance() {
0 Q% {3 a+ h Q' Q0 e if (instance == null) {
) y/ P) `$ J4 Q3 Q! o. u2 O* c instance = new Singleton();
' z2 H6 p6 }0 p; p) \; ~ } ( y7 C) u& j- m+ h# ~7 t
return instance; ( L+ m6 \+ Y: K" g
}
5 U# o" N ]2 l( a3 y+ s}. |+ ?" n8 U/ h+ h1 `# U
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)+ i( @( s+ r! z3 M" b' C- h1 Y
public class Singleton {
5 B' ?2 p: _& n8 g/ [7 E7 A9 M private static Singleton instance;
* M# d2 y% q3 r. x2 \' c5 V5 f+ b3 y5 b1 l0 t
private Singleton (){} # o& O% c/ W8 D. B+ X: |2 V
( ^6 @$ J! x6 S" ?( K! c$ w; B public static synchronized Singleton getInstance() { , E9 R/ {* x$ H# c% x0 j: {
if (instance == null) {
0 D6 Y9 o+ w1 v. q instance = new Singleton();
4 x( W5 c% e, Q: T/ B! N( k }
" b5 o1 d1 z7 K: f7 S return instance;
1 R0 c4 U0 L- b$ U }
" T% R+ i W6 b- O8 v1 `7 X}
3 t3 u/ g( m8 x6 p. O. _, ]6 j, H2 T$ d* F& P4 d3 }+ y( N
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
* ]/ X9 r9 e; G* r//双重校验锁+ l4 ^/ x. `% Y8 ]
public class Singleton {$ c5 {' J7 E% @) C+ T- {) i
private volatile static Singleton instance;# Q) d4 x) F- T1 }3 @( D- N
& o9 d7 b' z9 i$ t
private Singleton() {9 A! p* J2 ?, Y6 e. \1 o u
; d/ P' X/ Y5 Z! \
}5 n) w1 C! Q3 Y: ~" u* q) ?
% r; C; z" h: o" k. n public static Singleton getInstance() {
) w& N7 i; B/ |" M4 _, H2 j9 M" D if (instance == null) {
5 r) K, |; c5 } synchronized (Singleton.class) { q) v8 v, U: F, j& S1 W
if (instance == null) {+ C9 n1 r, H0 I
instance = new Singleton();( l9 G' y. |, d0 P
}- t3 G" `6 I! M6 v) O6 ^
}/ y$ p( b8 T4 n L* ]6 y
}) q$ ?* E- P/ ~. n0 a
return instance;
4 k/ M" u8 v0 Z1 Q, S/ k5 \ }
* {0 s# u% L: u" @6 ?}5 I. ]$ T0 i( ~
9 I V* j: h2 E
5 p: V8 e+ o/ Q4 ^- ?# |4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 / w! w+ }' a; m0 D" L
//饿汉式6 U+ D+ c. T+ U% m ^' U. N
public class Singleton {
, c7 o$ _2 g3 K private static Singleton instance = new Singleton();
S0 d+ X2 p1 X) v ?( ]* y5 j$ R# s, _3 _
private Singleton() {
: F: {+ x+ t1 i6 N
# y2 e2 ^" D- E2 M2 c& A+ e }7 ]; e; r Z7 Z0 a
+ a: F5 Z$ d2 F' r1 w1 K9 r public static Singleton getInstance() {5 D/ ?1 ] Y i# i0 g* r/ T
return instance; j; m+ u, R2 c8 _4 Y! A. G
}
; Y+ n9 ?( {4 l: }}
7 ?( g9 H3 D4 O' [* R3 i/ h
8 q% e4 g8 g7 w9 M+ a( M5 G% @( t! G9 \4 c% C7 X7 |0 }
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类" D" y' K. d2 N
public class Singleton {
) w# g# S- }& K1 i9 m private static class SingletonHolder {
* s7 k6 y8 i2 Y: g3 c private static final Singleton INSTANCE = new Singleton();1 H0 p( |5 l6 _8 t
}
) K8 ]. R% D1 }* m4 K6 }+ |1 \0 q$ [: n
private Singleton() {
S8 M" w& N5 n. U. y1 Z
1 V; r& M$ c; p }
+ l. C w9 c! Z; G- n0 F# u3 W" d+ R2 ~7 Y+ D, a) c
public static final Singleton getInstance() {
7 r% `1 y. a9 }7 R" @& D! K& S return SingletonHolder.INSTANCE;& q1 ?/ G, s2 {7 w) s* Y! ~
}
$ h# ^: ^2 N9 U4 T2 W}+ k o7 T3 u u
% S6 w! d. D1 O0 P* B6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 4 c8 k7 C5 t3 a
//枚举0 z9 f# H6 J: q7 _ w+ ~ t6 V
public enum Singleton {
* C$ ^9 ?: d5 z2 ] INSTANCE;
- R% |: b& s/ Q& n) H' i8 m, G- G% ]+ g6 w& I O6 I
public void whateverMethod() {
; i# U: c( ]$ u+ S& n2 h: L
2 \/ _( X) ~+ t }
5 }2 G) P5 v Y6 F/ Y1 O0 M* D/ j}
' m7 Z* m H8 u% q0 t, E4 {' d
/ K7 A. n3 T0 s8 S8 k
总结$ c+ e; F8 b' A+ j9 P7 p/ a# j
/ t+ C$ l2 i0 S$ m% P0 k: m一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
: g4 j+ C4 a$ F# d) y* PPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~) H/ ~5 x; r1 z
————————————————$ J: y t: c& V& Z, H$ d3 _1 q0 C
0 S/ H" a5 @6 T& O1 h; I' {0 h5 U4 q' g9 ]) r! C) H$ X
: z: x; z; T& I2 ]; t0 H$ k2 C6 _8 w' [0 Z) |( W; Y, e
( Y2 c5 B( U+ w2 U; J9 q% y2 L& c0 J8 C4 p$ L m+ o
2 I6 h) Z& Y: O0 l8 b
+ A5 b, \) V% U0 m# Q5 R
: e8 Y9 Q. g' e7 o8 Z( V( U原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764' l+ N# {. |/ t5 M
7 R$ R+ Z+ a- ?, q' l% M
* z# K* f; f$ I8 z; a |