浅谈单例模式的实现方式
1 N2 I& d" O( K% @单例模式(来自菜鸟教程)1 [. i7 T" A0 U/ g
/ x) t) E" ^" X4 D
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
3 X) N' n. i* f2 r" r" z单例模式的要求5 k1 B6 |4 Y3 ~. m! P$ v
- p: D# t6 L7 X5 e
构造方法必须私有化(确保只有自己能创建)' a8 J$ l) N2 |( r; \
以静态方法返回实例(外界不能通过new来获取到对象)+ q$ F8 I7 n# T5 S) x, S7 c7 ]
确保对象实例只有一个(只对类进行一次实例化,以后都直接获取第一次实例化的对象)
( P* F( @+ r; t9 _/ H. F8 _( V单例模式的实现
: Y. |9 g! c. W- P# C; \' u& c$ {8 i0 ^6 }+ V. n; N# W
1、懒汉式(线程不安全)
! r6 T* ^) H! h6 Y9 f
; p1 c: }9 d2 i3 w- `描述:这种方式是最基本的实现方式,但是不支持多线程。因为没有加锁,在多线程不能正常工作 J$ R- D+ O5 h' h/ Q5 m
//懒汉式(线程不安全)4 E: q2 q) _5 E& @+ } G" a7 ^
public class Singleton {
5 p& Q. n. E7 o, I4 o3 V private static Singleton instance;
+ v. u' @2 c ]0 q
: o; c) B+ Y( o t, E7 m2 S private Singleton (){}
3 e$ y; B7 T* `! D; S) i# ^: U9 m( Z7 V5 w6 |3 @) J2 |$ e
public static Singleton getInstance() {
( B. w1 c0 {2 H: h if (instance == null) {
$ j) d0 d6 }* X4 x" h instance = new Singleton();
! Y* z+ A, m' M0 k6 M } 9 O: Q+ ^* P5 h1 H1 N8 N
return instance; ! O: A$ x+ L' w) u
}
2 o3 k0 ^8 ?+ X}. `3 X( J2 S, I& D
2、懒汉式(线程安全) 描述:能够在多线程下正常工作,但是,效率极低 //懒汉式(线程安全)& e M6 G% P* f3 P D
public class Singleton {
2 @' ^* n7 Z5 W9 @8 _( L private static Singleton instance;
8 u) j! C+ o" S8 A$ S! D9 {: V
4 |) n: `4 s5 S4 F0 h! Y0 j private Singleton (){}
( Q0 s/ v* X5 P% U/ S1 R2 w5 s; B8 a0 d6 q3 r( V0 S6 c
public static synchronized Singleton getInstance() {
/ f5 F) v2 E, ]$ W& j if (instance == null) {
' G+ `+ C! ^: Z! j! C+ l( u$ { instance = new Singleton();
4 s3 C5 W1 F4 p4 A: b } ! T- t6 B- r+ w' j" n% V
return instance;
: |* H! q4 T2 o4 f* E, I+ J: f8 _! m }
( h' Q. t/ j* j }}3 B' e# v7 n* @
7 @9 n9 \1 H8 @& O3、双重校验锁(DCL,即double-checked locking)(线程安全) 描述:对懒汉式(线程安全)的优化,采用双锁的机制,安全且在多线程情况下能保持高性能 . ~. R! _ i# _/ m) W8 K% D2 |
//双重校验锁 P, J% n/ F6 V- h5 g: W& `1 H
public class Singleton {8 b: Y, i1 D7 ]7 |) f; e
private volatile static Singleton instance;
2 A/ n O$ v' J* _! A: [; k7 l5 v: F4 [3 c
private Singleton() {
- f4 q# M, ?/ M0 q. X, N& K
l- G# J/ B% c }
/ X/ P3 i6 q! O6 h( Y9 u8 U5 q" h0 C E$ w5 O" a
public static Singleton getInstance() {
1 W" [2 ~& l. |% b1 Q if (instance == null) {
' ^4 E6 I+ e$ ?2 h( T6 m9 ] synchronized (Singleton.class) {6 }6 x3 s( R3 c% {% ?9 ]1 _. b
if (instance == null) {
: l. b% Q* I! X3 j6 e( X instance = new Singleton();# T1 T# |, J' G5 T" u3 J: [. @5 I
}! X6 U+ d7 @& ]1 {) E
}/ k4 d3 a; R X' f
}
9 f k: V4 _0 J; d0 y' ^& T return instance;
/ {( b: C4 `7 |2 k& T5 n6 q }
) S/ s* B( l$ x: W}& D3 C2 N) m1 U( `
+ J5 r! E& c9 `6 E6 b( Z
# X( J7 M2 N( x! c+ s" h9 A& ~) ~
4、饿汉式(线程安全) 描述:这种方式比较常用,但容易产生垃圾对象 0 m* z( C/ C. t7 a" k
//饿汉式: ~& a2 W0 }) j4 ^/ e
public class Singleton {
$ c: B9 p; Q4 L private static Singleton instance = new Singleton();0 k6 s, K* o5 q) X* T& L3 B. h
: n! g+ C* i4 ] private Singleton() {2 s! \ g" C' X$ l/ T2 ?
. W* y8 Q9 f" C: F5 `4 Y- e
}
) Z$ P* f/ t5 \0 x6 X Q$ D0 q) J& Z7 r
public static Singleton getInstance() {, y' u* h9 W2 f: y. j; k& u
return instance;& O9 e7 d- d+ v/ {$ M
}
; Y- d! ^. i5 w3 q+ T8 U7 ]}
8 U' w+ B& V, M* c0 u1 o* p3 D) Z, b( x- G2 j5 H. y7 g
a2 Y6 y/ w" S
5、静态内部类(线程安全) 描述:这种方式达到跟双重校验锁一样的效果,这种方式只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用 //静态内部类2 I1 ]0 h# T0 o6 N K" O% E
public class Singleton {* K" a+ f& T* i. N$ S8 ~1 C
private static class SingletonHolder {
! J/ ^& b* {! a; z$ p& c& N private static final Singleton INSTANCE = new Singleton();
! A" n: j- t) _) L' @ Q5 X }% m$ }4 `% B. R$ V; _0 p- ~
/ p9 ^1 S/ p6 I6 H+ H; u- V private Singleton() {
' f! f8 E+ U s' d$ Y# C3 N
: Z! ~& r4 F9 F5 ]" q! P7 H }0 g$ j' I: d |- V: ^: U6 @1 j
9 P S% c ^( w" I# {( b public static final Singleton getInstance() {
4 A) B0 k E0 \5 J return SingletonHolder.INSTANCE;; X6 r2 D3 T8 P! i5 s
}. M2 v5 Y A% `8 G" V
}4 R) ^0 _% \ k) a$ }, G: u7 P
3 A& I( ?( T' z8 A9 s) [6、枚举(线程安全) 描述:这种方式还没有被广泛采用,但是这种实现是单例模式的最佳方法。更简洁、自动支持序列化机制、绝对防止多次实例化
/ J8 p1 I) y3 L X6 [//枚举6 x( ]$ P0 i) x
public enum Singleton {8 g7 \* B8 ]& ?% p
INSTANCE;
1 g4 n- \7 A i7 N5 N I% T0 |2 [5 z/ v* Y- [- J2 d
public void whateverMethod() {+ Q; a9 o9 x' C! ?. U
2 q. T/ ^% h% E& U- s6 o; O& h0 o }
' ^8 a, H ^, j6 w3 X}( f$ r% I! F) f
+ Q$ z! B* v. S* ~$ V+ K
4 m9 s! h' r, Z: v4 n总结
. n( h' @( j6 j5 M8 C7 v
9 N9 `6 P" p1 r- d7 \% x+ F一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第4种饿汉方式。只有在明确实现lazy loading时,才会使用第5种静态内部类方式。如果涉及到反序列化创建对象时,可以使用第6种枚举方式。如果有其他需求,可以考虑使用第3种双重校验锁方式。
8 V7 B8 o0 s; S+ h8 QPS:开始面临着春招,好多面经都有说到设计模式。最常见的面试题就是讲一讲单例模式的实现和理解,所以我写一下,加深我对单例模式的理解和印象。觉得对你有帮助的话可以点点赞,谢谢啦~~~
8 X$ y( J( J9 t* i————————————————, N. n+ j% X/ Y) m, {: i
6 Y% d2 i7 w' y4 a4 c* C! Y. n2 d: w
/ t, Q9 I4 M' q
; C5 E% f# q8 i& S7 L( U, N. G0 a! V3 L) e" f! m5 R
: }* ]+ ], y. p5 c8 t% V
2 S+ Y& ?; F5 ?, N0 o" }9 d/ b$ ~; @ V) s% L- K- r
9 c- L, d; ?/ j原文链接:https://blog.csdn.net/weixin_37686415/article/details/105164764( m" e) [$ G* U7 I3 _) O: D
$ e1 t. f9 d9 |& k" m
6 e0 W7 ^ L4 R' |/ Q" W. N
|