浅谈单例模式的实现方式
- C9 [3 D) n$ F+ g单例模式(来自菜鸟教程)5 G" }/ l$ U9 q, |. X
* N' a5 `( @) R. V) E
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
9 Z' W, f$ w4 \单例模式的要求0 e$ N: o4 r3 ?- O2 K+ Q1 a% w
, w7 ` Z) D }; }5 B6 c
构造方法必须私有化(确保只有自己能创建)
8 _% e3 B ?6 Z% [: A7 V+ Z3 ~以静态方法返回实例(外界不能通过new来获取到对象)
: t* F4 M" Y/ w- e# d确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)1 e) R; m. Y, E3 A
单例模式的实现
1 i) [! |0 N0 X# J
$ `; ?- q% \8 _3 l- ^ K. {3 c1、懒汉式(线程不安全)2 z/ {* e1 k+ ^* w% Q$ o* Q/ w$ U
% G3 D2 Q) O; s7 M描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作; S | Z( I* L# {& p; ]
//懒汉式(线程不安全)" n O( Y( h' Y
public class Singleton {
$ G+ Y! w% H( v private static Singleton instance; " U0 m3 n. J( @
9 n9 i' V, n3 v3 v4 X0 i. A
private Singleton (){}
0 h. z( V- ~- V7 h4 {4 X( V6 c
6 f6 s5 @! K& ?' v7 }& [5 z public static Singleton getInstance() {
" F+ [1 k$ ~- \ if (instance == null) {
$ O( W9 A/ S3 C, U+ I5 T M" R instance = new Singleton();
. d C2 K6 {2 l* I* F } * \4 k# \9 A( w' c& `7 B% s# j- w
return instance; ) n- `9 M. z- G1 P, Q5 L8 n
} 7 U' `$ X% b p6 E
}
0 m9 Z3 e6 I. W- n# |6 T n2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
. N# i' F) o/ b6 k9 Ypublic class Singleton {
* K7 u$ d7 \8 s private static Singleton instance; 2 c7 I# o) A7 k* f7 {
: y9 j4 a' ?' w, D% A
private Singleton (){} 4 e. {! N4 Z" A4 F# c8 Q
) h/ X8 ]' G; J: O public static synchronized Singleton getInstance() {
: Z- F s+ G& I! w/ c; [8 v6 L( i if (instance == null) {
% |) I6 f( v) [3 `1 l instance = new Singleton(); * }4 i5 i1 z9 H+ k% ~8 M
} 1 q* `" U; L% ~7 i. O1 R! N
return instance;
) o$ B9 g% p/ v }
1 A9 L' J" u- m3 D# d}4 X. S7 t- `8 h/ V+ b/ K
5 g N G! P& j3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
3 f, e9 u2 y+ y B# I' A//双重校验锁- N4 G4 M6 w6 g7 S+ A/ {
public class Singleton {
' |* f3 n( z% I& V) N6 Z private volatile static Singleton instance;( K2 ^# d- a3 O# R& V: w3 J
; M+ o& ]% `4 k* R$ ]7 B* x8 N
private Singleton() {- k, z% {9 x4 ~. l0 B0 ^- S
% U3 A# @5 }, b9 i" g }
' @% w8 C; O+ X- e6 z& R; j) [( h, ]) u5 J1 Y1 p8 O
public static Singleton getInstance() {
G( D2 y8 p$ k8 \# w' ` if (instance == null) {8 b1 ]4 A& r0 K- b* P7 h. H- t' M
synchronized (Singleton.class) {
! X3 n, _- m6 }2 Z4 r9 s if (instance == null) {' g4 n a; Z3 y3 l
instance = new Singleton();7 ?2 _5 o2 _! W* u5 ^- n8 j
}' I7 u2 F: ?6 D9 y2 G( K+ L
}+ x$ v$ t- R9 O* C3 N
}2 H8 i) g3 V: i6 E/ @5 h7 k: f
return instance;3 O( G q( P5 p5 V$ |
}7 {& f; e! V# {: v- G3 V
} l6 g! S8 q5 n Z' g0 m% n9 ^
( G) Q T$ l7 n
2 z7 d- i Z: q8 H; r+ d4 e1 j. e, v
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 3 A- }" Q$ C, ?- u( w/ t# Q0 r) t
//饿汉式
! E/ ^: A# \3 n/ ?! @$ ypublic class Singleton {
- \: r8 a4 w& R3 \- t* L private static Singleton instance = new Singleton();
# B- x$ W* z, j0 m3 U, Z
+ y7 Z/ s, E- ?6 m9 O private Singleton() {4 U8 N+ c0 Y% {" R3 m7 P
' g2 P$ R- h( [. R, U }
& |" o! d) z6 h3 [6 l7 O! ~5 x( t, g- ?: b; T4 s8 v$ {
public static Singleton getInstance() {
8 e6 z" y/ l' C return instance;7 A7 r M* I' x. G8 \; C
}3 S: p% e9 j) V* x, K, v+ j+ f7 v
}
/ G) L7 w) E" l3 y* O
' H; g1 j4 m0 B5 k/ \1 _4 Z/ [. A- ]- T
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类( m6 @* z$ s9 J, R! y
public class Singleton {
' G2 }) `; k( w1 V- {. p private static class SingletonHolder {
5 {' |8 d% v! A3 E. T# h3 g8 S private static final Singleton INSTANCE = new Singleton();0 `" U- [- V. ^0 V
}
3 e, w% r5 u& m. W) G0 u1 _/ y, |, C% Y" L- {
private Singleton() {
1 ~! |- T- [% M5 K, K
$ P( h/ ]3 \$ m5 T! _ }9 I0 ^% f' P$ b" q
: j( G! k. Y! c4 t
public static final Singleton getInstance() {
% {2 {* ]% ]. g7 m return SingletonHolder.INSTANCE;: r0 D0 }* [7 G
}0 [' v& M; g9 ]" f4 y' z6 g
}9 T+ B3 t# Y* a8 l# C( a0 R7 T1 u
; @8 G; f$ P: L
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 ) X# W! L1 [% S# ^ O( @
//枚举
. l4 U- `' d0 f! npublic enum Singleton {
2 m5 r9 ?# Z( e5 u INSTANCE;: q" i5 T, N) U8 S6 N
: t L# T, o/ a: N v public void whateverMethod() {
. s c! p5 _5 s# |
) a% b+ z* A% F, W- D2 Z5 Z }7 a" ^- e' c. e0 ] m0 a
}7 C& L$ r8 B( c4 \( S, [
# y& [/ c$ e( ^' d2 M7 }: [3 h! T( v" J
总结# |3 s5 \! P6 S
4 A/ v9 H! G% G8 e一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
1 }, g* X8 w3 V2 G) C: j, RPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~8 b g! Q6 \$ [
————————————————' q* q8 x3 f) O# Y, H
& x; ]7 Y7 Q. M. e6 \3 G8 s
: s: ~" T# A, V7 e- [6 y+ H$ [: T3 ]/ k% @* F+ l5 Q" o
% R. c1 d+ X; i) S: k7 A3 I$ d
/ y N, i- x/ e9 W! [: V# N c* c. z" E
; b, f, n" |) V
7 u4 N; ?5 a) R! L
~# k% n& s4 c2 F0 {2 n原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764! \6 a! G1 h2 f& c' F3 G J
! U3 k4 N9 Z$ U9 q8 X# G3 r# ]& ` _
+ b: O4 B$ m Y1 L) r |