java 单例模式5种写法
学习整理
饱汉模式(懒汉模式)
1 // 饱汉
2 // UnThreadSafe
3 public class Singleton1 {
4 private static Singleton1 singleton = null;
5 private Singleton1() {
6 }
7 public static Singleton1 getInstance() {
8 if (singleton == null) {
9 singleton = new Singleton1();
10 }
11 return singleton;
12 }
13 }
优点:懒加载启动快,资源占用小,使用时才实例化,无锁。
缺点:非线程安全。
饱汉模式(懒汉模式)--线程安全
1 public class Singleton {
2
3 /**
4 * 定义一个变量来存储创建好的类实例
5 */
6
7 private static Singleton uniqueInstance = null;
8
9 /**
10 * 私有化构造方法,好在内部控制创建实例的数目
11 */
12
13 private Singleton(){
14 }
15
16 /**
17 * 定义一个方法来为客户端提供类实例
18 * @return 一个Singleton的实例
19 */
20
21 public static synchronized Singleton getInstance(){
22
23 //判断存储实例的变量是否有值
24 if(uniqueInstance == null){
25 //如果没有,就创建一个类实例,并把值赋值给存储类实例的变量
26 uniqueInstance = new Singleton();
27 }
28
29 //如果有值,那就直接使用
30 return uniqueInstance;
31 }
32
33 /**
34 * 示意方法,单例可以有自己的操作
35 */
36
37 public void singletonOperation(){
38
39 //功能处理
40
41 }
42
43 /**
44 * 示意属性,单例可以有自己的属性
45 */
46
47 private String singletonData;
48
49 /**
50 * 示意方法,让外部通过这些方法来访问属性的值
51 * @return 属性的值
52 */
53
54 public String getSingletonData(){
55
56 return singletonData;
57
58 }
59
60 }
优点:同上,但加锁了。
缺点:synchronized 为独占排他锁,并发性能差。即使在创建成功以后,获取实例仍然是串行化操作。
饱汉模式(懒汉模式)--双重加锁检查DCL(Double Check Lock)
1 public class Singleton {
2
3 /**
4 * 对保存实例的变量添加volatile的修饰
5 */
6
7 private volatile static Singleton instance = null;
8
9 private Singleton(){
10
11 }
12
13 public static Singleton getInstance(){
14
15 //先检查实例是否存在,如果不存在才进入下面的同步块
16
17 if(instance == null){
18
19 //同步块,线程安全的创建实例
20
21 synchronized(Singleton.class){
22
23 //再次检查实例是否存在,如果不存在才真的创建实例
24
25 if(instance == null){
26
27 instance = new Singleton();
28
29 }
30
31 }
32
33 }
34
35 return instance;
36
37 }
38
39 }
优点:懒加载,线程安全。
注:实例必须有 volatile 关键字修饰,其保证初始化完全。
饿汉模式
1 public class Singleton {
2
3 //4:定义一个静态变量来存储创建好的类实例
4
5 //直接在这里创建类实例,只会创建一次
6
7 private static Singleton instance = new Singleton();
8
9 //1:私有化构造方法,好在内部控制创建实例的数目
10
11 private Singleton(){
12
13 }
14
15 //2:定义一个方法来为客户端提供类实例
16
17 //3:这个方法需要定义成类方法,也就是要加static
18
19 //这个方法里面就不需要控制代码了
20
21 public static Singleton getInstance(){
22
23 //5:直接使用已经创建好的实例
24
25 return instance;
26
27 }
28
29 }
优点:饿汉模式天生是线程安全的,使用时没有延迟。
缺点:启动时即创建实例,启动慢,有可能造成资源浪费。
Holder模式
1 public class Singleton {
2 /**
3 * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
4 * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
5 */
6 private static class SingletonHolder{
7 /**
8 * 静态初始化器,由JVM来保证线程安全
9 */
10 private static Singleton instance = new Singleton();
11 }
12 /**
13 * 私有化构造方法
14 */
15 private Singleton(){
16 }
17 public static Singleton getInstance(){
18 return SingletonHolder.instance;
19 }
20 }
优点:将懒加载和线程安全完美结合的一种方式(无锁)。(推荐)
备注:
1. 全局共享,独一份;
2. 构造函数不暴露(如果暴露便不能保证一份),自己负责自己的构造;
3. 懒汉式:Lazy load,用到才加载,非线程安全。如何保证线程安全呢:
(1) synchronized getInstance()。
(2)双重检查加锁(volatile)。
4. 饿汉式:一开始就申请好,浪费了点资源,但其线程安全。
5. Holder模式:
(1)改成内部类,由JVM保证线程安全性。