浅谈单例模式的实现方式
7 h; f9 c( O# ]8 _9 P单例模式(来自菜鸟教程)
8 l |% I0 z- G2 H# `) U$ ?8 x1 q7 O0 B/ b6 f* O, Z( b- r
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。 z) Y/ X. [/ F% o2 x7 t2 J6 V
单例模式的要求
. G# ?* K5 U$ N. S7 o
7 L* [! ^4 Z# T3 e6 Y* I6 m0 X0 s构造方法必须私有化(确保只有自己能创建)
5 N" B+ M$ |. E5 `: ~以静态方法返回实例(外界不能通过new来获取到对象)6 p3 H [" Z# a6 e! y9 B
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)5 Z9 q! i' C' ^# N1 {
单例模式的实现
* ^) |' f1 t5 H& y3 J. U$ [7 r' }0 @: l& M0 W- F
1、懒汉式(线程不安全)
) J" K2 k+ j8 {- s3 J
2 p! b6 t6 X ?: Y2 R5 k. {1 B描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作
A: L* g$ U' x" v& E& l; i//懒汉式(线程不安全)
! f- I! y$ w- a4 N# l8 R3 n8 c% `6 B: Hpublic class Singleton { ! [/ w$ r8 O- X" i
private static Singleton instance;
) ?, k- ]4 i% z) s5 M4 C
# T# J" i* i( Q: ` private Singleton (){}
% T& Q2 s [- H* l6 Y- z8 I! @+ T* k: {" z$ c$ J
public static Singleton getInstance() {
: \! O, G5 v4 s; l( f5 a) e if (instance == null) { , S+ V5 P. C1 B" R7 Q9 R5 q
instance = new Singleton(); ( q0 c! s8 i# O
} . O1 H! G3 i- t: ]3 }5 L1 v$ K$ b6 v
return instance;
) A& ]1 @3 \" p% f5 p9 s* I }
! `& O5 F1 |# e}
' Y# F: ]' J# b* m) Q& \5 |, k2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)
& j" G6 w1 _# u7 spublic class Singleton {
+ i2 M/ X! w$ ~% h0 f4 t9 B private static Singleton instance;
; T' E, C* l7 f2 C) D3 E- \: H; C: }* ~
private Singleton (){} 3 F* k# Y8 y: {
2 l: j) @9 e' [( `8 v8 L
public static synchronized Singleton getInstance() { / p L$ b) k$ D
if (instance == null) {
. Z+ k! q. A" G, z" X" _" l instance = new Singleton();
% |' j+ V2 c2 T! w- A% F5 Z+ ] }
; B. R( \$ i7 `: ?: | return instance; ! k8 E( _5 G7 `& z* g9 u8 ^0 d3 V
}
9 N8 _7 }+ A/ T2 V! x}) M F6 I3 ^6 m( U1 V2 }4 Z
8 Z( B* c, m) T9 i+ q3 _3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 ) I$ Y: H7 {8 m5 `3 v G; x( k
//双重校验锁2 L7 `" |# ]; K/ q
public class Singleton {
; _% A3 c& ~/ [+ W3 P1 u2 l! j( E) k( r private volatile static Singleton instance;4 S; n) r, D* o
5 |; ~: [ D1 r. ^& K4 i private Singleton() {
$ P& Q& A( B; p; W5 w' e3 U$ u# Q$ L ?
}+ i, v; K6 ?# I$ s! _
/ a2 U1 l* f& S. [) a1 v7 S0 p" s
public static Singleton getInstance() {3 s& g/ U% P; x( a4 ~7 V$ N0 ~
if (instance == null) {; y+ Z) m; A4 t
synchronized (Singleton.class) {
]& P6 P* @/ `2 y/ O if (instance == null) {
5 T' ]& W6 ]( p/ t V# m2 } instance = new Singleton(); P0 y' \% y9 P. p! X8 N( j" @
}
2 a3 W9 H) o1 V! P2 n h7 m }. x7 F& @9 e7 d- S( D% J$ o
}
, h! R* ^3 P: B( U4 j% d return instance;
% T* X" g# C! X, Y }* N! ]# L* A/ J' K# V0 \# I
}& u- g* j5 _% o8 T0 f6 ^7 u( U$ [
) a8 S' |- F1 k w( G
5 R" L; {$ c( R
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象
* Y2 c+ Z' R& I! `1 m//饿汉式
1 U, s1 Z/ b T/ [/ c. [public class Singleton {3 w+ G3 i5 f6 i' y1 P
private static Singleton instance = new Singleton();
8 o' z- S* ^# a) C3 D, ?
0 C' G, D2 L$ o0 r6 [* ^& Y private Singleton() {. m6 b; _. M4 J4 L
' B. j- Q+ k( m2 ?
}
& o0 A/ J B g4 M5 N% p8 y* e" D7 U/ X* I* z; s
public static Singleton getInstance() {% J* B" t0 Y' B: y3 _- q
return instance;
" h5 S% }. y( G! Z2 Q) n }6 F7 ^* k3 F$ i1 S7 a8 g
}& d9 J) M( J+ O* K
" t; Z/ i0 R u9 J6 p+ n* R" K9 _/ c' K' `+ i
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类+ y- [% B5 }1 q
public class Singleton {
4 @6 k$ N7 O; V! U0 D private static class SingletonHolder {
- V/ ^. t0 H5 Q8 h- M6 }8 Q% | private static final Singleton INSTANCE = new Singleton();
4 g# W; r" G+ K6 a% g, M. k: U' O9 W: s }
% ?) Y7 s. \ i0 F' X' Q) k, t' I
private Singleton() {
4 m& y, W$ B6 a' G0 g6 Y- h* C' B7 { [
}5 j/ l2 c- l3 V; [* ^# m
9 x: K/ ^8 I8 t( }$ U2 L
public static final Singleton getInstance() {
6 y% Y/ J. Y4 o! X. R& a) _7 F return SingletonHolder.INSTANCE;
L/ f$ p* z, E! p( R7 X }# U9 o3 z/ p6 g& f# j; D
}& I4 `! T, A% a* z
0 K3 M: p* U% ~' p, [3 V
6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
6 v, b- b/ }2 k+ e% e% y! u//枚举
9 p3 M E5 }5 ]( |5 Y& d ?public enum Singleton {6 B- I' Z; t- |$ @/ j
INSTANCE;6 R* G. d) ~ j. c& g) H( ~
( [7 T0 t- F, a0 ?0 E" W! x public void whateverMethod() {
$ E% e, t( J, l
, \0 h7 A" a' L% k: g, e/ F1 n1 W* H }! @/ k* k. p l {! U! _
}
+ d$ w% b$ T+ Q# F* |" d) A5 O
. i3 Z) b' ] w2 Z$ k9 ?2 \4 p9 e9 ^8 d% x
总结! l2 N1 x* ^' b; o
$ J& C- i7 X3 j4 ]1 Z: y7 H. u) ^+ w- Q一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。1 Y0 F$ ?2 f9 A. Q- }2 b) h
PS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
+ I" F+ R, I) X. _6 e————————————————
* A0 D2 @; p/ b$ \& z# [: g+ y0 B2 ]0 P- M
; p. P' K& V* A* v5 n* J; C; A( V' N( M
1 }! l0 v' I) n7 U u: O3 [5 r0 _& e$ n
/ U9 U; e* }, L
4 Z6 v% m8 i p; P# \2 x9 v4 G
* l# ?1 r) x/ D4 t: t8 p( a: w$ |+ V) {; k
原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764
2 m7 \) C* B! g L
4 t& U9 Z7 f. C9 z6 W1 P& _5 q( P; J+ u7 F! `
|