单例核心技术,阻止实例的创建,在java面向对象中创建实例的唯一方法即构造方法,因此将构造方法私有化阻止了外部实例化(通过反射可以进行破解);通过内部静态属性能够保持对象的生命周期即jvm的结束。
饿汉模式
/**
* 饥饿模式在类加载的时候就进行实例化
* 类的加载过程中会对静态变量进行内存分配(类引用会实例化)
* 类的加载天然线程安全,不存在线程安全问题
*/
public class Hunger
{
private static Hunger instance = new Hunger();
private Hunger()
{
System.out.println("单例 - 饥饿模式");
}
public static Hunger getInstance()
{
return instance;
}
}
懒汉模式
/**
* 懒汉模式在使用的时候实例化(加载的时候不会实例化)
* 懒汉模式存在线程安全,故加入同步代码块也因此效率会受影响
*/
public class Lazy
{
private static Lazy instance = null;
private Lazy()
{
System.out.println("单例 - 懒汉模式");
}
//同步避免多实例
public synchronized static Lazy getInstance()
{
if (null == instance)
{
instance = new Lazy();
}
return instance;
}
}
双检测锁
/**
* 双检测锁会进行两次null检测
* 提高了线程访问效率,在第一次访问时会慢些因为进入同步快,之后不会进入线程同步快
* 实现了懒加载又提高效率
* 但是由于jvm底层模型图以及指令排序问题可能会存在问题,故不推荐使用
*/
public class DoubleCheckLock
{
private static DoubleCheckLock instance = null;
private DoubleCheckLock()
{
System.out.println("单例 - 双检测锁");
}
public static DoubleCheckLock getInstance()
{
if (null == instance)
{
//需要线程同步,避免多实例
synchronized (DoubleCheckLock.class)
{
if (null == instance)
{
instance = new DoubleCheckLock();
}
}
}
return instance;
}
}
内部静态类
/**
* 内部静态类在外部类加载时不会被加载
* 类的加载时天然线程安全
* 即实现了懒加载又提高效率
*/
public class InnerClass
{
private InnerClass()
{
System.out.println("单例 - 静态内部类");
}
private static class Inner
{
private static InnerClass instance = new InnerClass();
}
public static InnerClass getInstance()
{
return Inner.instance;
}
}
枚举单例
/**
* 枚举是基于jvm实现的,在jvm启动后会创建且天然单例
* 无法懒加载
* 枚举在编译后:public static final Enumeration INSTANCE;
* 会自动实例化
*/
public enum Enumeration
{
INSTANCE;
private Enumeration()
{
System.out.println("单例 - 枚举");
}
public static Enumeration getInstance()
{
return INSTANCE;
}
public void test()
{
System.out.println("test");
}
}
测试类
public class App
{
public static void main(String[] args)
{
Hunger hunger1 = Hunger.getInstance();
Hunger hunger2 = Hunger.getInstance();
System.out.println(hunger1 == hunger2);
Lazy lazy1 = Lazy.getInstance();
Lazy lazy2 = Lazy.getInstance();
System.out.println(lazy1 == lazy2);
DoubleCheckLock doubleCheckLock1 = DoubleCheckLock.getInstance();
DoubleCheckLock doubleCheckLock2 = DoubleCheckLock.getInstance();
System.out.println(doubleCheckLock1 == doubleCheckLock2);
InnerClass innerClass1 = InnerClass.getInstance();
InnerClass innerClass2 = InnerClass.getInstance();
System.out.println(innerClass1 == innerClass2);
Enumeration enumeration1 = Enumeration.getInstance();
Enumeration enumeration2 = Enumeration.getInstance();
System.out.println(enumeration1 == enumeration2);
}
}