1. 什么是单例模式?
单例就是确保某一个类在软件应用的整个生命周期只有一个实例,而且能够自行实例化并向整个系统提供这个实例
2. 单例模式的特点?
1)单例类只能有一个实例(饿汉思想:保持饥饿,直到创建单一对象 懒汉思想:初始化应用时,就创建单一对象)
2)单例类必须自己创建自己的唯一实例(构造函数必须是private类型,不允许其他程序使用new对象)
3)单例类必须给所有其他对象提供这一实例(提供统一的接口供其他程序调用)
3. 单例模式有哪些用途?
节省资源,防止一个全局使用的类频繁的创建和销毁对象
比如说:
- Windows 是多进程多线程的,在操作同一个文件的时候,就不可避免的出现多个进程和多个线程同时操作一个文件的现象,所以必须通过一个唯一的实例来进行操作
- 在线程池,缓存,日志对象,对话框,打印机等都要设计成单例
4. 单例模式的分类
1.懒汉模式
只有首次获取成员变量时【getinstance()】才去初始化,如果单例对象一直没有使用,我们就不去初始化它,这样就可以节省系统的资源【不过这种开销往往不会太大】
2.饿汉模式
在类加载的时候就实例化成员变量,避免线程的同步问题,在【getinstance()的时候去获取它,此时对象实例已经初始化】
5. JAVA单例模式
- 饿汉模式:
1 | package com.example.jingbin.designpattern.singleton.ehan; |
2.懒汉模式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73package com.example.jingbin.designpattern.singleton.lanhan;
/**
* 3.单例模式的懒汉式
*/
public class SingletonLanHan {
private SingletonLanHan() {
}
/**
* 3.单例模式的懒汉式[线程不安全,不可用]
*/
private static SingletonLanHan singletonLanHan;
public static SingletonLanHan getInstance() {
if (singletonLanHan == null) { // 这里线程是不安全的,可能得到两个不同的实例
singletonLanHan = new SingletonLanHan();
}
return singletonLanHan;
}
/**
* 4. 懒汉式线程安全的:[线程安全,效率低不推荐使用]
*
* 缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。
* 而其实这个方法只执行一次实例化代码就够了,
* 后面的想获得该类实例,直接return就行了。方法进行同步效率太低要改进。
*/
private static SingletonLanHan singletonLanHanTwo;
public static synchronized SingletonLanHan getSingletonLanHanTwo() {
if (singletonLanHanTwo == null) {
singletonLanHanTwo = new SingletonLanHan();
}
return singletonLanHanTwo;
}
/**
* 5. 单例模式懒汉式[线程不安全,不可用]
* <p>
* 虽然加了锁,但是等到第一个线程执行完instance=new Singleton()跳出这个锁时,
* 另一个进入if语句的线程同样会实例化另外一个Singleton对象,线程不安全的原理跟3类似。
*/
private static SingletonLanHan instanceThree = null;
public static SingletonLanHan getSingletonLanHanThree() {
if (instanceThree == null) {
synchronized (SingletonLanHan.class) {// 线程不安全
instanceThree = new SingletonLanHan();
}
}
return instanceThree;
}
/**
* 6.单例模式懒汉式双重校验锁[推荐用]
* 懒汉式变种,属于懒汉式的最好写法,保证了:延迟加载和线程安全
*/
private static SingletonLanHan singletonLanHanFour;
public static SingletonLanHan getSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = new SingletonLanHan();
}
}
}
return singletonLanHanFour;
}
}
3.内部类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.example.jingbin.designpattern.singleton.inclass;
/**
* 7. 内部类[推荐用]
* <p>
* 这种方式跟饿汉式方式采用的机制类似,但又有不同。
* 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。
* 不同的地方:
* 在饿汉式方式是只要Singleton类被装载就会实例化,
* 内部类是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类
* <p>
* 优点:避免了线程不安全,延迟加载,效率高。
*/
public class SingletonIn {
private SingletonIn() {
}
private static class SingletonInHodler {
private static SingletonIn singletonIn = new SingletonIn();
}
public static SingletonIn getSingletonIn() {
return SingletonInHodler.singletonIn;
}
}
4.枚举
枚举的方法暂时不写
所以,综上所述,
要么使用饿汉模式:直接在类中的私有静态变量直接初始化;
要么使用懒汉模式:使用内部类,进行初始化,当需要使用时,进行懒加载
6.javascript单例模式
因为JS是单线程的,所以JS中不存在线程安全的问题,下面
var Singleton = (function(){
var instantiated;
function init(){
return {
publicMethod:function(){
console.log('hello world');
},
publicProperty:'test'
}
}
return {
getInstance:function(){
if(!instantiated){
instantiated = init();
}
return instantiated;
}
}
})();
Singleton.getInstance().publicMethod();
参考博客:
http://blog.csdn.net/w2765006513/article/details/53743051
http://www.cnblogs.com/TomXu/archive/2012/02/20/2352817.html
更多设计模式整理文章:https://github.com/zhehuaxuan/DesignPattern