一、饿汉式单例
1、第一种写法
package com.ckw.singleton.hungry;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 14:24
* @description: 饿汉式
*/
/*
饿汉式单例
它是在类加载的时候就立即初始化,并且创建单例对象
优点:没有加任何的锁、执行效率比较高,
在用户体验上来说,比懒汉式更好
缺点:类加载的时候就初始化,不管你用还是不用,我都占着空间
浪费了内存,有可能占着茅坑不拉屎
绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题
*/
public class HungrySingleton {
private static final HungrySingleton h = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance(){
return h;
}
}
2、第二种写法:饿汉式静态块单例
package com.ckw.singleton.hungry;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 14:32
* @description: 饿汉式静态块单例
*/
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
static {
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton() {
}
public static HungryStaticSingleton getInstance(){
return hungrySingleton;
}
}
二、懒汉式单例
1、第一种写法
package com.ckw.singleton.lazy;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 14:35
* @description: 懒汉式
*/
public class LazySimpleSingleton {
private LazySimpleSingleton() {
}
private static LazySimpleSingleton lazy = null;
public static LazySimpleSingleton getInstance(){
if(null == lazy)
lazy = new LazySimpleSingleton();
return lazy;
}
}
2、第二种写法
package com.ckw.singleton.lazy;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 14:41
* @description: 双重检查
*/
public class LazyDoubleCheckSingleton {
/*
以后章节会进行讲解
TODO
volatile: 内存可见
禁止指令重排序
*/
private static volatile LazyDoubleCheckSingleton lazy = null;
private LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton getInstance(){
if(null == lazy){
synchronized (LazyDoubleCheckSingleton.class){
if(null == lazy){
lazy = new LazyDoubleCheckSingleton();
//1.分配内存给这个对象
//2.初始化对象
//3.设置lazy指向刚分配的内存地址
//4.初次访问对象
}
}
}
return lazy;
}
}
3、第三种写法
package com.ckw.singleton.lazy;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 14:50
* @description: 静态内部类
*/
//这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题
public class LazyInnerClassSingleton {
//防止通过反射进行创建多个实例
private LazyInnerClassSingleton() {
if(LazyHolder.LAZY != null){
throw new RuntimeException("不允许创建多个实例");
}
}
//每一个关键字都不是多余的
//static 是为了使单例的空间共享
//保证这个方法不会被重写,重载
public static final LazyInnerClassSingleton getInstance(){
//在返回结果以前,一定会先加载内部类
return LazyHolder.LAZY;
}
private static class LazyHolder{
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
三、防止反射和序列化破坏单例
1、怎样防止反射破坏单例?
![在构造方法中判断](https://i-blog.csdnimg.cn/blog_migrate/db408bdd97f361f9cc721156fa62834d.png)
2、怎样防止序列化破坏单例?
![重写readResolve](https://i-blog.csdnimg.cn/blog_migrate/bfd630bd7075cf66cb1ae8cd372348ae.png)
四、注册式单例
1、枚举单例
package com.ckw.singleton.register;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 15:37
* @description: 枚举单例
*/
//枚举不能被序列化和反射破坏
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
2、容器式单例
package com.ckw.singleton.register;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 15:47
* @description: 容器式单例
*/
//Spring中的做法,就是用这种注册式单例
public class ContainerSingleton {
private static Map<String,Object> ioc = new ConcurrentHashMap<>();
private ContainerSingleton() {
}
public static Object getInstance(String className){
synchronized (ioc){
if(!ioc.containsKey(className)){
Object o = null;
try {
o = Class.forName(className).newInstance();
ioc.put(className, o);
} catch (Exception e) {
e.printStackTrace();
}
return o;
}
return ioc.get(className);
}
}
}
五、伪线程单例(ThreadLocal)
package com.ckw.singleton.threadlocal;
/**
* @author ckw
* @version 1.0
* @date 2020/6/8 16:02
* @description: 伪线程式单例
*/
//同一个线程内,获取得对象都是同一个
public class ThreadLocalSingleton {
private static ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton() {
}
public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}