浅谈单例模式的实现方式/ N$ r- A1 Y9 o* m# Z' w5 q
单例模式(来自菜鸟教程)
% k+ ^0 S0 G- V2 L! J" d2 W$ e3 C, W( }" n# t! _3 v) n- j+ E
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
3 z3 _. r/ `3 f& I8 I1 t* K6 t单例模式的要求
" K* |+ U# x2 _, W2 p1 ~( ^! y# ~9 O1 m
构造方法必须私有化(确保只有自己能创建)
7 e$ Z K1 d2 E9 ]/ G& j, M以静态方法返回实例(外界不能通过new来获取到对象)5 t7 q" J9 X' P: x5 u7 h h1 ?. u
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)# ^$ J8 b+ K. U' r8 @" H
单例模式的实现
4 W7 G8 @% ^2 ]( p2 J$ }
. @( m" H7 L$ i9 \" @8 I6 J1、懒汉式(线程不安全)8 ]$ K0 w6 g) d- a: M0 `: {+ ^
* @# [* w: d, G6 t4 [# Q描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作" t9 B9 [ g# S$ k; u4 K
//懒汉式(线程不安全)7 L% p3 I; v. \; s8 l+ {5 }
public class Singleton {
) u0 Q H7 Q4 [' j private static Singleton instance;
3 d& ]; c& h" o/ h0 B' \, B5 N
$ {, k8 f9 r! `5 W6 V7 A private Singleton (){}
' |/ m3 O+ ~6 J. G" {8 @8 y1 G; h6 |; a2 ?$ S# ]- r8 K
public static Singleton getInstance() { ?# E, }/ B/ c! \! k& r b: L
if (instance == null) { ( p3 r2 t' d' v. M0 c
instance = new Singleton();
: j% d; K& o& B8 i3 G% n* ~ }
5 P* @1 C- L0 d3 | return instance; # z+ E6 X3 x' P% `4 E
}
% f1 G0 f9 x4 f4 k9 p) U1 [}
0 m/ y$ Y3 n/ }/ x `2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
% ]8 {: [) q& u% Rpublic class Singleton { I9 q) x" s* ~* S" Z7 {. i4 U
private static Singleton instance; 6 ]1 I% X h& [$ N; Y
. t: M2 ^3 x2 ]; Q
private Singleton (){} ' e/ L! U$ f. X, g! {4 _" R
" n x5 A6 ~; t3 d4 u public static synchronized Singleton getInstance() {
" J1 E+ F( m4 j/ Q& F$ R8 y# j( Z4 p if (instance == null) {
7 n4 N; c5 p$ e* F8 u9 ?$ @ instance = new Singleton(); E+ ]$ @0 R% u$ v6 o" Q( }
} ! T: X' w4 z# S* L4 }9 m
return instance; - v5 Q, g R2 f9 ~
}
2 a* u% N+ L, G J/ h4 X0 Y}$ V ?0 K, R# g% H6 L9 y
4 x8 w+ L3 T8 ?+ Q; p
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能
! L" ^. T% \& z//双重校验锁
- @# D7 G2 n& d+ v' Z: ]public class Singleton {% A+ B P z8 s' H
private volatile static Singleton instance;
9 w' l2 U/ v: C& D$ t% q" o1 i: m. }2 b+ w5 r( L' p
private Singleton() {
" C( d# x. q; R# K- S8 B7 u8 ~, M. B8 E N& i1 f }; `
}) W6 C$ O. ^. T0 _ Z+ e+ |, ?2 [2 X
. _% }" ?) m) v; X3 G3 a; g7 y public static Singleton getInstance() {. d# d( q2 r6 \' {" J
if (instance == null) {
9 T+ J( Q4 \4 j" z6 t3 y" u7 z) J! G synchronized (Singleton.class) {
5 b. L8 [( e' i2 K if (instance == null) {8 U8 `) B5 M. r- p2 t# x# |
instance = new Singleton();* K. u% v+ m6 T6 Y
}
/ B& e8 J5 r# ?& [ }
4 {4 U* |9 ?* G( }/ ? }; y* x/ f) j6 }$ i0 a: Q K7 @. f
return instance;
+ k: V4 k! U% a) m; b }
: T$ u% B; A" k}2 `; {( D( H6 \+ h$ I/ N) v# v
4 X: S, I# i. ?
9 G& s8 f2 y9 u$ p4 l4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 % n9 M1 Y$ M" s
//饿汉式
1 B* y2 U: k0 }$ x1 E( P& {9 k/ D4 qpublic class Singleton {
. D+ s" F. d. K' P3 Y y! @7 @ private static Singleton instance = new Singleton();% N9 j/ _0 a& ]& J! x. E
: }$ u, P. v/ c
private Singleton() {' o3 s$ t$ g; n2 U _ |& P( m
$ t6 F$ o& x5 V8 k! F! j, l
}
: b8 `- ?/ V) [) D
/ m% ^0 j) A7 u- W) i public static Singleton getInstance() {
7 s# r7 v) O6 `2 G. ?- ?7 ^ return instance;3 o8 Z+ B2 o- c
}
9 ~+ p9 E5 j& g9 ^}
# |4 v- ^- H* k8 f$ F
/ U' ^( l. x! ] J: c- J+ P0 n% G8 O4 F$ N" ]' ]! G- N! O5 @6 R
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
; _5 c2 H9 ]- ]/ j- n4 j5 hpublic class Singleton {6 l6 K# P5 k+ ~1 a7 ?
private static class SingletonHolder {
+ R) z! g0 A. H/ A6 N8 w private static final Singleton INSTANCE = new Singleton();/ M: @' i. ?+ P& P
}
# n& J4 n; k$ _ j/ z8 G, o( T" P- t! B5 C4 J9 @
private Singleton() {) `5 }" |$ {! R% r# ^& S
$ |' z3 k3 J- {+ W
}# W! j& v% b7 y
E$ E1 `: n3 b! C3 J @# _4 S( ?5 c public static final Singleton getInstance() {
4 c8 v8 u8 @/ d) G% U3 V2 I return SingletonHolder.INSTANCE;
$ I5 ?6 W$ |* W- c% \) m }
9 t9 D! H3 i# c* x}
0 V6 V5 {: E% W$ Q
- E) p* S ^) k9 O5 z e& [% ?/ H+ G6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
9 n4 t& O* ~( ]3 J) a//枚举- z, r3 c/ F" C) O
public enum Singleton {
6 d" N. P' \& m. E; j' P$ t* | INSTANCE;
% S( r6 k1 ^7 M+ T4 h3 c+ z$ o( h, Q& y- r6 O4 J1 p4 D
public void whateverMethod() {
! U8 q2 j0 v* K- p% h) [/ O% F
+ A5 D W" h* ] }# M$ A: S- t8 C% R* M: @
}1 I" U5 h, w- V; N
5 J' `2 Q9 R% a' p
) ?: ~, Q% G- p- {6 E0 Z" q总结
. }" W M$ Y6 O7 G Q, x$ Z: g- v! t: I+ D1 I- B" @% g+ @
一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。" P- N! Y7 `+ ^/ k- c. }% V: X
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
l& @! B, s, e' o1 E————————————————1 @; U. v7 h( U7 s* @2 t
9 r' H+ t# R7 `! V3 n0 m4 M
1 t' F/ A& L& D% z R, j/ |, g6 b3 W2 N9 s# k G% e3 x! c# N
, r1 c+ q0 K1 T( v
* {1 z- _1 x/ m) N8 ^: z. Z4 P# l/ L+ o1 ^+ @
, }$ W% j, }. E$ `9 B% U* [5 Q
( J5 A+ h: a1 `9 C. S1 x
3 R1 C+ _$ z: C* n) B% }+ m1 i原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
; [: d3 P4 ^ y- y# M3 E; K2 s6 D. O1 D! z/ f& R
! ]. m) V/ R& O t2 e. K* K |