一、什么是单例模式?
单例:一个类模版,在整个系统运行过程中,只允许产生一个事例(有且只有一个)。
二、保存单例的技术方案有哪些?
- 饿汉式:在实例使用之前,不管用不用,都先new出来,避免了线程安全问题;
/**
* @ather: lucksheep
* @date: 2018/8/6 19:46
* @description: 饿汉式
*/
public class Hungry {
private Hungry(){}
//先静态、后动态
//先属性、后方法
//先上后下
private static final Hungry hungry=new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
- 懒汉式:默认加载的时候不实例化,在需要用到的时候才实例化,延迟加载;
第一种:
/**
* @ather: lucksheep
* @date: 2018/8/7 11:18
* @description: 懒汉式
*/
public class LazyOne {
private LazyOne(){}
private static LazyOne lazy=null;
public static LazyOne getInstance(){
if(lazy==null){
lazy=new LazyOne();
}
return lazy;
}
}
第二种:
/**
* @ather: lucksheep
* @date: 2018/8/9 14:25
* @description:
*/
public class LazyTwo {
private LazyTwo(){}
private static LazyTwo lazy=null;
public static synchronized LazyTwo getInstance(){
if(lazy==null){
lazy=new LazyTwo();
}
return lazy;
}
}
第三种:
/**
* @ather: lucksheep
* @date: 2018/8/9 14:25
* @description:
*/
public class LazyThree {
private static boolean initialized = false;
//默认使用LazyThree的时候,先初始化内部类
//如果没使用,内部类是不加载的
private LazyThree(){
//防止反射
synchronized (LazyThree.class){
if(initialized == false){
initialized = !initialized;
}else{
throw new RuntimeException("单例已被侵犯,不给你看!");
}
}
}
public static final synchronized LazyThree getInstance(){
return LazyHolder.lazy;
}
private static class LazyHolder{
private static final LazyThree lazy=new LazyThree();
}
}
- 注册登记式:每使用一次,都往一个固定的容器中去注册并且将使用过的对象进行缓存,下次去取对象的时候,就直接从缓存中取值,以保证每次获取的都是同一个对象;IOC中的单例模式就是典型的注册登记式单例
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @ather: lucksheep
* @date: 2018/8/10 15:48
* @description: 注册登记式
*/
public class RegisterMaps {
private static Map<String,Object> registerMaps=new HashMap<>();
//如果要安全的 ConcurrentHashMap
public static RegisterMaps getInstance(String name){
if(null == name){
name = RegisterMaps.class.getName();
}
if(registerMaps.get(name) == null){
registerMaps.put(name,new RegisterMaps());
}
return (RegisterMaps) registerMaps.get(name);
}
}
- 枚举式:这个很简单我就不说了。
/**
* @ather: lucksheep
* @date: 2018/8/10 15:57
* @description: 枚举
*/
public enum RegisterEnum {
ONE,TWO,Three;
}
- 序列化与反序列化单例:如果要保证单例安全,只需要重写 private Object readResolve(){}这个方法。
/**
* @ather: lucksheep
* @date: 2018/8/10 16:07
* @description: 序列化单例
*/
public class Serializes implements Serializable {
private static final long serialVersionUID = 3239595067725719650L;
private Serializes(){}
public final static Serializes serializes=new Serializes();
public static Serializes getInstance(){
return serializes;
}
/**
* 加上可以保证单例是安全的
* 原因:序列化与反序列化中的一个协议,为了实现实例化后,
* 对象重复利用,它可以实现 readResolve() 这个方法,这个方法是JVM自动去调用的
* @return
*/
private Object readResolve(){
return serializes;
}
}