浅谈单例模式的实现方式2 @0 e9 j: H3 o' S0 g- n
单例模式(来自菜鸟教程)" d4 Z$ Z! f7 x8 x. a9 L
+ U& a) l8 M+ d9 S" r8 ?
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。" F# D6 a- `; W, p$ [6 s
单例模式的要求
R$ H2 t1 L& s+ f" k* G4 g) a+ _
* N8 h7 [: B$ F: r构造方法必须私有化(确保只有自己能创建)
6 m4 s. }* C7 ]$ \& e' D$ {以静态方法返回实例(外界不能通过new来获取到对象)
) i: a+ E6 S i0 ?( J% T: F确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)9 d* d6 Z3 u( K$ E3 [' q% y; f
单例模式的实现( Q3 _# N, u, P* k$ Y2 A4 k
6 L. X5 j4 }+ K Y, Y% r, W
1、懒汉式(线程不安全)
# Z9 i1 L" U, X& z+ B8 H
8 W* W# L& L+ u, z4 c8 i描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作* a; E7 _: V4 t+ d
//懒汉式(线程不安全)
3 L1 C6 H1 Y4 K5 I3 s; X. P, K- w) ]! rpublic class Singleton { 4 o( c! y' k. ?; I
private static Singleton instance;
: z( E* ~& h( _6 B1 ~3 p; [+ [- P
! m# G* g9 ~8 u% N private Singleton (){}
/ n" h% M _% z0 A ^9 x7 _& x o3 E5 K
! m, c4 e K4 w3 j9 @7 q3 [ public static Singleton getInstance() {
7 h' D- a+ s Z if (instance == null) {
, j8 B& }5 n0 J! i instance = new Singleton(); 9 m" D8 e7 E. [
} 0 o1 \/ W) L* h/ a" A
return instance;
+ }' @* V1 z$ r# ? }
/ Y ~) [, I; m; e$ h}
/ t, a" ^! z# F3 `& R% |2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
% K, d% T& R! W) G8 Vpublic class Singleton {
9 X: i- Y0 b9 C) _" n private static Singleton instance; 4 h3 Q- G" a* `5 Z& w2 ~
/ \4 X, ?# x& Z( P1 p/ i! g private Singleton (){}
4 `. J: a9 u0 x$ `2 v" C$ Q8 c7 T( I5 ^0 N9 [ G' x
public static synchronized Singleton getInstance() { - ^1 u4 Q- U, g% G) E
if (instance == null) { ( L: m; K2 J' M. J
instance = new Singleton();
7 p' L. i& o) p4 t g }
% W, b& {' p; Z return instance; / c7 V" R0 [, J5 w. ~
} $ i, m8 o5 X$ X8 y, ?6 |' e; G" ]
}& q4 ^. V4 g3 z$ F, W
- \0 ?. N1 m7 R5 @4 }
3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 & e6 E+ A8 Y, ]% T% L+ B
//双重校验锁- U& R7 X9 r: q, w1 o& |% Y2 ]5 m
public class Singleton {1 A& u4 S: N) T0 D! `
private volatile static Singleton instance;1 Y# X) ]5 ?1 e% ^8 s# |2 c/ H
. f/ {# P r5 @7 R' r; \, j1 C) y9 T! H private Singleton() {
7 K1 f( C; ?( e7 h$ |
2 _+ W, V- X+ P" m* ` } P' j! |, S, e/ A
7 N! ^2 ~% Y! s) |1 C
public static Singleton getInstance() {
3 T! ^3 y# R7 M" H if (instance == null) {
5 k& \& g6 z& v3 g1 p* J& A- `, I synchronized (Singleton.class) {
6 C: _+ W+ U4 i/ b/ O1 p& E if (instance == null) {
]0 V( r3 q1 S% K9 w k3 f instance = new Singleton();
. b% u5 m$ m! } }6 t# o1 ]0 H" m6 o. J
}
9 [8 u) X/ x: K7 P0 D! f; A }7 u9 H- @8 N8 ~0 U- E$ o
return instance;
* Q: m! k& }, d4 U4 ]( t }
8 ?# d1 q: E, q& q% [* P) x7 Z" @+ i}
9 b/ f8 z& T# c8 c
5 i4 R U: w/ u* Q* m+ W/ O* a4 l, t( u; @0 m8 t
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 : v' b! n, X1 m5 @* y+ e C6 X$ w
//饿汉式
, g+ v% z* v# l# [public class Singleton {
, P7 P" f6 u8 K# N$ h1 _) T private static Singleton instance = new Singleton();
/ h3 A; b c1 h4 b4 k
1 e, T0 p/ f) y, L9 X private Singleton() { X2 \. A3 Y9 G0 S9 _/ a
- w- n8 D* A w. C
}
" g3 K: I5 Q' P$ c) u' J
+ H- h) E1 `, f public static Singleton getInstance() {& T, H: K0 o1 A; V* a
return instance;/ l/ k- q4 d- d( `5 _$ ^
}
1 B& p& I/ g ~& E2 ]}
* x: B5 {7 X- R# T! E4 v; ]% g1 r( h8 s$ p8 d
; F9 N' d" y2 W% [; F% D) E$ v5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类
6 t' ?6 B/ H7 Z$ ^8 c' \8 w2 Wpublic class Singleton {* k, u8 p4 Y- p9 e z+ q
private static class SingletonHolder {
2 m0 E. K& @ S5 z0 J5 c/ [ private static final Singleton INSTANCE = new Singleton();! j: a: l; d# e3 \* H
}4 ^2 | P( p" p0 v1 O4 }
8 X& o5 u3 k$ t private Singleton() {
0 Q q6 m1 o' B0 h" g# M$ }, ?, F8 i: L
}
& P0 ?8 r: v# y/ ^) E
8 b* Z! h2 S; F s5 E9 S public static final Singleton getInstance() {
" B- V$ o6 f4 M& d, P- a return SingletonHolder.INSTANCE;& i+ ~; K3 s& E/ U6 A2 M6 Z# F! g
}3 u j4 j$ y8 H8 q
} W# `5 o! z2 Y9 B8 f- b
; B! N }/ U0 b3 y6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化 ! G' j3 \' i5 ]5 i
//枚举( i x: d- Z" a! x# E6 P
public enum Singleton {
0 e2 ^0 j$ ~. ~( N( O) d INSTANCE;$ g0 k* L$ Q: ]& o
# E% k! Q7 Y1 v$ J& G public void whateverMethod() {
6 Q) A8 |: T# w8 S2 n2 Q1 M/ ^' R. f( ~, }9 P8 W
}2 q) n, g7 R1 }
}3 K* F9 j* }% Q' j
$ N! W) X% v8 Z+ F3 e: n$ N+ x6 H# q4 o) D2 V2 k$ S/ t- y
总结; W" j( s; Q1 Z. K5 {
+ V Q! a& {8 w一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
6 N, ]7 T% e7 e/ F# s! ]PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
- U9 B7 z w& @$ @' Q( `' w————————————————4 u! g( |( G' i. g
2 ?. j# G8 l& D1 V, I
: S5 k5 G" n# r: T
& A. @+ t j. M( m$ U/ t: r" P
1 k9 J e0 c% c4 C
3 ?# h, _7 D. U1 ?( U
8 ~1 O9 S% z0 R+ V2 w7 o) n. c, ^( E' m( u$ X! g
& ?' S2 P/ T0 F. c/ b9 ], ^+ [
- A2 o8 g. m# S- T. P; Q原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764: n& G, s5 v; H) c! _9 z) \6 B
6 S/ u! O( O' {+ F$ p$ V* c
0 u4 u; M9 e8 ]- Z* c |