概述:单例模式就是保证在内存中只存在一个实例。像Mgr,Factory这种就只需要一个实例。单例的核心在于私有化构造方法。
饿汉式:简单,推荐使用!
/**
* 饿汉式
* 类加载到内存后只实例化一个单例
* 私有化构造器
* 缺点:不论用到与否类加载完成就完成实例化
*/
public class Hungry {
private static final Hungry INSTANCE = new Hungry();
// 构造方法私有化
private Hungry(){
}
private static Hungry getInstance(){
return INSTANCE;
}
}
懒汉式
为了解决饿汉式的问题,懒汉式的缺点式按需加载。有两种实现方法,一种式同步方法一种是同步代码块。
同步方法:
/**
* 懒汉式2.0
* 把方法变为同步方法之后就解决了线程不安全的问题
* 但是带来了效率的降低
*/
public class Lazy2 {
private static Lazy2 INSTANCE;
private Lazy2(){
}
public synchronized static Lazy2 getInstance() throws InterruptedException {
if (INSTANCE==null){
INSTANCE = new Lazy2();
}
return INSTANCE;
}
}
同步代码块:双重检查
/**
*懒汉式3.0
* 通过同步代码块实现
*/
public class Lazy3 {
private static volatile Lazy3 INSTANCE;
//volatile关键字可以保证多线程模式下内存的可见性和禁止指令重排
private Lazy3(){
}
public static Lazy3 getInstance() throws InterruptedException {
if (INSTANCE==null){
//这里可能被线程打断 已经完成判断之后被打断 打断的线程完成实例的创建 打断回来之后此线程会再一次创建实例
synchronized (Lazy3.class) {
//所以进入同步代码块还需要再判断一次
if (INSTANCE == null)
INSTANCE = new Lazy3();
}
}
return INSTANCE;
}
}
静态内部类方法
在外部类加载时不会被加载,此时解决了懒加载的问题,又由JVM保证线程安全,因为在JVM中一个类只能被加载一次。
/**
* 静态内部类方式
* JVM保证单例 因为在JVM中一个类只能被加载一次
* 但是在加载外部类时内部类不会被加载 可以实现懒加载
*/
public class StaticInnerClassMethod {
private StaticInnerClassMethod(){
}
//定义一个内部类 内部类中有一个外部类的变量 需要时加载内部类的变量
private static class StaHolder{
private final static StaticInnerClassMethod INSTANCE =
new StaticInnerClassMethod();
}
public static StaticInnerClassMethod getInstance(){
return StaHolder.INSTANCE;
}
}
枚举
这是目前实现单例模式是目前最完美的一种实现方式,使用枚举类型的特性(枚举类型无法被反编译)完成了单例模式,有效防止反序列化。
/**
* 枚举类实现
* 是目前为止最完美的解决方案
* 由于枚举类型的特殊性他不能够被反序列化
*/
public enum PerfectMethods {
INSTANCE;
//测试
public static void main(String[] args) {
for (int i = 0; i < 100 ; i++) {
new Thread(()->{
System.out.println(PerfectMethods.INSTANCE.hashCode());
}).start();
}
}
}