【Java设计模式】单例模式


### 1. 概述
> 单例模式是确保某一个类中有且只有一个实例。java

----------
### 2. 饿汉式单例
``` java
public class SingletonInstance {
private static SingletonInstance mInstance = new SingletonInstance();
// 默认私有构造方法
private SingletonInstance(){}
// 静态工厂方法
public static SingletonInstance getInstance(){
return mInstance ;
}
}
```
在饿汉式单例中,静态变量会在私有构造方法中初始化,这时候惟一的实例就被建立出来了,饿汉式主要使用到的是**空间换时间**的思想,在类还在加载的时候,对象实例便已经建立好了。缓存

----------安全

### 3. 懒汉式单例
```java
public class SingletonInstance {
private static SingletonInstance mInstance = null;
// 私有默认构造方法
private SingletonInstance(){}
// 静态工厂方法
public static synchronized SingletonInstance getInstance(){
if(mInstance == null){
mInstance = new SingletonInstance();
}
return mInstance;
}
}
```
对于懒汉式单例的处理,使用了``synchronized``参数修饰工厂方法,用来在多线程环境中解决同步问题,懒汉式主要是使用到的是**时间换空间**的思想,在获取实例的时候进行判断,只有在须要的时候才去建立对象,节省内存空间,可是缺点就是实现的方式是线程安全的,这样会下降访问的速度。多线程

----------
### 4. 双重加锁单例
```java
public class SingletonInstance {
private volatile static SingletonInstance mInstance = null;
private SingletonInstance(){}
public static SingletonInstance getInstance(){
//先检查实例是否存在,若是不存在才进入下面的同步块
if(mInstance == null){
//同步块,线程安全的建立实例
synchronized (SingletonInstance .class) {
//再次检查实例是否存在,若是不存在才真正的建立实例
if(mInstance == null){
mInstance = new SingletonInstance ();
}
}
}
return mInstance;
}
}
```
双重加锁机制指的是,在每次进入``getInstance``方法先不一样步,而是进入方法后,先检查实例是否存在,若是不存在才进行下面的同步块,这属于第一重检查,进入同步块事后再检查实例是否存在,若是不存在,就在同步的状况下建立一个新的实例,这属于第二重检查。这样便只须要同步一次,并减小了在屡次同步状况下进行判断浪费的时间。
这种实现方式会使用到**volatile**关键字,意思是被**volatile**修饰的变量的值,不会被本地线程缓存,全部对该变量的读写都是直接操做共享内存,从而保证线程正确的处理该变量。
> **volatile**关键字在**JDK5**以前的版本中加锁失败,注意之。并且**volatile**关键字会屏蔽掉虚拟机中的一些必要的代码优化,所以虽然能实现双重检查加锁机制的单例,但并不建议大量采用。优化

那有什么方案能够既能达到延迟加载,又能实现线程安全的目的呢?线程

-----
### 5. Lazy Initialization Holder Class模式
```java
public class SingletonInstance {

private SingletonInstance(){}
/**
* 类级的内部类的实例与外部类的实例没有绑定关系,并且只有被调用到时才会装载
*/
private static class SingletonHolder{
/**
* 静态初始化,由JVM来保证线程安全
*/
private static SingletonInstance mInstance = new SingletonInstance();
}
public static SingletonInstance getInstance(){
return SingletonHolder.mInstance;
}
}
```
若是只是想简单的实现线程安全的单例,可使用以前的**饿汉式**方式。可是缺点就是会在类装载的时候初始化对象,形成空间的浪费。
那么只要解决了类加载时自动初始化对象的问题,即可以解决问题。所以能够采用类级内部类的方式去实现,这样的话,只有在须要的时候才会建立对象实例,也达到了延迟加载和线程安全的目的。
从实现过程来看,但调用`getInstance`方法时,它会读取`SingletonHolder.mInstance`,从而初始化,在这个类被装载的时候,也会初始化静态成员,而因为静态域的特性,只会初始化一次,而且由JVM来保证线程安全。
>- 什么是类级内部类?
被`static`修饰的成员内部类才是类级内部类,若是没有被`static`修饰则被称为对象内部类,并且类级内部类与外部类对象不存在依赖关系,只有在第一次使用的时候才会被调用。
>- 多线程默认同步锁知识?
在多线程开发中,咱们主要使用`synchronized`来对互斥锁进行同步控制,可是某些状况下JVM已经为咱们进行了同步控制了,主要有:
1. 静态初始化方法初始化数据时;
2. 访问`final`字段时;
3. 在建立线程以前建立对象时;
4. 线程能够看见要处理的对象时;对象

----------
### 6. 枚举式单例
```java
public enum SingletonInstace{
// 定义一个枚举元素,它表明了一个实例
mInstance;
// 单例的操做
public void singletonOperation(){

}
}
```
使用枚举的方式既使得代码简洁,并且也由JVM来保证序列化机制,防止屡次实例化,是最佳的实现单例的方式。内存

相关文章
相关标签/搜索