原文来自:www.toutiao.com/i6759419236…
一、单例模式的定义
单例模式是指在系统运行期间,一个类有且只有一个实例对象,这个对象已经创建,就不再改变,这样模式就是单例模式。
单例模式在生产中应用得非常广泛,我们在用spring IOC时,可以选择单例创建;redisTemplate连接redis的工具类;网络中管理session的对象…
单例模式有两个重要的特点:(1)只会初始化一个实例对象,(2)全局提供统一访问,也就是说不能用new去创建对象。
二、单例模式的实现
1. 饿汉式
类加载时候创建,后续不在创建,这能保证运行期间只有一个实例对象,通常用静态变量实现;我们看代码
/***
* @description : 饿汉式单例模式,在内加载的时候创建实例对象
* 这种方式叫做提前创建,不管时候需要,在使用不好单例的情况下,最好用这种方式创建
* 普通的应用对内存的需求没有那么严格,这种方式省事又高效,不过多占用了点内存而已
* 当然在内存紧张,访问很大的网站或应用,慎重一些
*/
public class HungryManSingleTon {
private static HungryManSingleTon
instance = new HungryManSingleTon();
private HungryManSingleTon(){}
public static HungryManSingleTon
getInstance(){
return instance;
}
}
饿汉式的弊端在上述代码的注释中已经说明,就是在类加载就创建,不管是不是需要,是不是会用,什么时候用,是不管的。不过实现简单,还是有很强的操作性。
2. 懒汉式
懒汉式并在是类加载的时候创建,而是根据需要的时候去创建,懒汉式写法有很多,我在此拿其中几种方式说明:
几种写法的公有部分
public class LazyManSingleTon {
private static LazyManSingleTon instance = null;
private LazyManSingleTon(){}}
1) 如果是空,则创建,不为空直接返回
/**
* 很常用的方法,需要的时候在创建,如果多的线程同时访问的时候,可能创建多个实例
* @return
*/
public static LazyManSingleTon getInstance(){
if(instance == null){
instance = new LazyManSingleTon();
}
return instance;
}
在没有多线程的情况下,没有问题,如果在客户端Android中就可以这么用,单用户访问存在并发,可以
2) 在并发的环境用synchronized方法
/**
* 采用synchronized关键字,作为同步锁,synchronized用到方法上时,用锁定的当前类
* 只允许在这个类的实例上需要的同步的操作只允许一个线程执行
* @return LazyManSingleTon
*/
public static synchronized LazyManSingleTon getSynchInstance(){
if(instance == null){
instance = new LazyManSingleTon();
}
return instance;
}
这种方法保证了同步,因为单例有一个实例,synchronized锁定的是类,同一时间只有一个线程访问,效率不高,但是保证了只会创建一个实例。
3) 用同步代码块创建
/**
* 采用同步代码块的实现单例,如果instance in null, 加锁,
* 在判断instance时候为空, 如果为空,则创建实例
* 为什么需要判断两次了,如果在高并发的场景了, 可能在一次判断的时候,另外的一个线程已经创建了实例
* 因为通常用单例模式对象,大而复杂的对象,创建于销毁都需要花费较大的代价才能完成
* 这种方式要比同步方法要更为优雅,在高并发的场景下,这种创建方式是比较常用
* @return instance
*/
public static LazyManSingleTon getSychBlockInstance(){
if(instance == null){
synchronized (instance){
if(instance == null){
instance = new LazyManSingleTon();
}
}
}
return instance;
}
这种方式只会在线程判断对象为空的时候创建,而且保证了只创建一个对象,是一种不错的实现方式。
4) 内部类的方式创建
/**
* 利用饿汉式的内部类, 解决懒汉式阴sychronized同步的性能问题
* @return
*/
public static LazyManSingleTon getInnerInstance(){
return SingleTonFactory.instance;
}
private static class SingleTonFactory{
private static LazyManSingleTon instance = new LazyManSingleTon();
}
这种方式只值得提倡的,性能问题与线程安全问题都解决了
单例模式看起来简单,用好不是那么简单,给出几种写法示例供参考,但是一定要主要每种写法的问题所在。