目录
1、单例模式介绍
单例设计模式就是采取一定的方法保证在整个程序中,对某个类只能存在一个对象实例,并且该类只提供一个 取得其对象实例方法。
单例设计模式的实现有如下几种 方法:
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全,同步方法式,执行效率不高)
- 懒汉式(线程安全,同步代码块,执行效率不高)
- 双重检查式 (线程安全,执行效率高)
- 基于Java静态内部类(线程安全,执行效率高)
2、饿汉式单例模式
2.1、静态常量方式
2.1.1、代码实现
/**
*@Description 饿汉式 静态常量方式实现单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
/**
* 创建静态对象实例
*/
private final static SingleCase instance=new SingleCase();
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
return instance;
}
}
2.1.2、优缺点
- 优点:写法比较简单,在类装载的时候就完成了实例化,避免了线程同步问题。
- 缺点:在类装载的时候就完成了类的实例化,没有实现类
懒加载
的效果,如果这个类从来没有被使用过,会造成内存浪费
2.2、静态代码块方式
2.2.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
private static SingleCase instance;
/**
* 在静态代码块中,创建对象实例
*/
static {
instance=new SingleCase();
}
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
return instance;
}
}
2.2.2、优缺点
基于静态代码块实现的单例模式,也是在类装载时就完成了类的实例化,避免了线程同步问题,但是没有实现懒加载
的效果,如果这个类从来没有被使用过,会造成内存浪费。
3、懒汉式单例模式
3.1、线程不安全方式
3.1.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
private static SingleCase instance;
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
if (instance==null){
instance=new SingleCase();
}
return instance;
}
}
3.1.2、优缺点
- 只有在使用到该类的时候才进行类的实例化,避免了可能造成的内存浪费。
- 只能在单线程环境下使用,在多线程环境下产生多个实例(一个线程进入到了
if (instance==null)
,还未来得及往下执行,同时另一个线程也执行到了if (instance==null)
,这时会产生多个类实例)
3.2、synchronized 同步方法
3.2.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
private static SingleCase instance;
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static synchronized SingleCase getInstance(){
if (instance==null){
instance=new SingleCase();
}
return instance;
}
}
3.2.2、优缺点
- 优点: 线程安全
- 缺点:执行效率低,每个线程想要获得类实例的时候,都要先获得当前类对象的锁,另外一个线程需要等待当前线程锁的释放
3.3、synchronized 同步代码块
3.3.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
private static SingleCase instance;
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
if (instance==null){
//同步代码块
synchronized(SingleCase.class){
instance=new SingleCase();
}
}
return instance;
}
}
3.3.2、优缺点
这种方法减少了锁的粒度,但是也会出现线程间相互等待锁释放的情况,执行效率不高
4、双重检查式
通过volatile
来确保将变量的更新操作通知到其他线程,在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞
4.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
/**
* 使用volatile 保证类对象,对其他线程可见
*/
private static volatile SingleCase instance;
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
if (instance==null){
//同步代码块
synchronized(SingleCase.class){
if (instance==null){
instance=new SingleCase();
}
}
}
return instance;
}
}
3.3.2、优缺点
-
如果多个线程同时了通过了第一次检查,并且其中一个线程首先通过了第二次检查并实例化了对象,那么剩余通过了第一次检查的线程就不会再去实例化对象,保证了加锁其实只需要在第一次初始化的时候用到,之后的调用都没必要再进行加锁。
-
线程安全、懒加载、执行效率高
5、基于Java静态内部类
5.1、代码实现
/**
*@Description 单例模式
*@author warybee
*/
public class SingleCase {
/**
* 私有化构造方法
*/
private SingleCase(){
}
private static class SingleCaseInner{
private static SingleCase INSTANCE=new SingleCase();
}
/**
* 公有的静态方法,返回对象实例
* @return
*/
public static SingleCase getInstance(){
return SingleCaseInner.INSTANCE;
}
}
5.2、优缺点
- jvm启动后 静态内部类不会被直接加载。 只有在使用静态内部类的时候,他才会加载,保证了延迟加载
- 外部调用
getInstance()
方法后,会触发InnerClass的加载,任意一个线程获取该【类加载】的锁后,就能保证StaticInnerClassSingleton首次给new出来,只有一个线程进入该内部类。加载完成后,static成员变量是唯一的。