定义
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
单例模式特点
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给所有其他对象提供这一实例
懒汉式
代码实现:
/**
* @author liouwb
* 单例模式
*/
public class SingletonPatternTest {
public static void main(String[] args) {
// 懒汉式
SingletonLazy lazy = SingletonLazy.getInstance();
SingletonLazy lazy1 = SingletonLazy.getInstance();
// 验证单例是否全局只有一个实例
System.out.println(lazy == lazy1);
// 输出对象信息
System.out.println("lazy :" + lazy);
System.out.println("lazy1:" + lazy1);
}
/**
* 懒汉式
*/
static class SingletonLazy {
//
public static SingletonLazy instance;
// 私有构造函数
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
}
- lazy和lazy1判断结果输出:
正常获取的实例比较:true
lazy :singleton.SingletonLazyTest$SingletonLazy@4554617c
lazy1:singleton.SingletonLazyTest$SingletonLazy@4554617c
Process finished with exit code 0
结论:
- 单例模式只有一个实例
- 懒汉式单例模式,线程不安全
饿汉式
代码实现:
- 代码演示:
package singleton;
/**
* @author liouwb
* 单例模式
* 饿汉式
*/
public class SingletonHungryTest {
public static void main(String[] args) {
// 饿汉式
SingletonHungry hungry = SingletonHungry.getInstance();
SingletonHungry hungry1 = SingletonHungry.getInstance();
// 验证单例是否全局只有一个实例
System.out.println("饿汉式正常获取的实例比较:" + (hungry == hungry1));
// 输出对象信息
System.out.println("hungry :" + hungry);
System.out.println("hungry1:" + hungry1);
}
/**
* 饿汉式
*/
static class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
/**
* 构造函数
*
* @return
*/
private SingletonHungry() {
}
/**
* @return
*/
public static SingletonHungry getInstance() {
return instance;
}
}
}
- 实例比较结果:
饿汉式正常获取的实例比较:true
hungry :singleton.SingletonHungryTest$SingletonHungry@4554617c
hungry1:singleton.SingletonHungryTest$SingletonHungry@4554617c
Process finished with exit code 0
结论:
- 获取实例为同一实例
- 饿汉模式在类被初始化时就已经在内存中创建了对象,以空间换时间,故不存在线程安全问题
检查锁单例模式
- 代码采用懒汉式演示,饿汉式代码基本相同,加锁效果一样
- 代码演示:
package singleton;
/**
* @author liouwb
* 单例模式
* 懒汉式 加锁
*/
public class SingletonLazyLockTest {
public static void main(String[] args){
// 懒汉式 加锁
SingletonLazyLock lazyLock = SingletonLazyLock.getInstance();
SingletonLazyLock lazyLock1 = SingletonLazyLock.getInstance();
// 验证单例是否全局只有一个实例
System.out.println("正常获取的实例比较:" + (lazyLock == lazyLock1));
// 输出相应对象
System.out.println("lazyLock :" + lazyLock);
System.out.println("lazyLock1:" + lazyLock1);
}
/**
* 懒汉式 加锁
*/
static class SingletonLazyLock {
//
public static SingletonLazyLock instance;
// 私有构造函数
private SingletonLazyLock() {
}
public static synchronized SingletonLazyLock getInstance() {
if (instance == null) {
instance = new SingletonLazyLock();
}
return instance;
}
}
}
- 输出结果:
正常获取的实例比较:true
lazyLock :singleton.SingletonLazyLockTest$SingletonLazyLock@4554617c
lazyLock1:singleton.SingletonLazyLockTest$SingletonLazyLock@4554617c
Process finished with exit code 0
结论:
- 加锁之后,线程安全
双重检查锁
- 代码:
package singleton;
/**
* @author liouwb
* 单例模式 双重检查锁
*/
public class SingletonDoubleCheckLockTest {
public static void main(String[] args) {
// 懒汉式 双重检查锁
SingletonLazyDoubleLock lazyDoubleLock = SingletonLazyDoubleLock.getInstance();
SingletonLazyDoubleLock lazyDoubleLock1 = SingletonLazyDoubleLock.getInstance();
// 验证单例是否全局只有一个实例
System.out.println("正常获取的实例比较:" + (lazyDoubleLock == lazyDoubleLock1));
// 输出相应对象
System.out.println("lazyDoubleLock :" + lazyDoubleLock);
System.out.println("lazyDoubleLock1:" + lazyDoubleLock1);
}
/**
* 懒汉式 双重加锁
*/
static class SingletonLazyDoubleLock {
//
public static SingletonLazyDoubleLock instance;
// 私有构造函数
private SingletonLazyDoubleLock() {
}
public static synchronized SingletonLazyDoubleLock getInstance() {
if (instance == null) {
synchronized (SingletonLazyDoubleLock.class) {
if (instance == null) {
instance = new SingletonLazyDoubleLock();
}
}
}
return instance;
}
}
}
- 结果:
正常获取的实例比较:true
lazyDoubleLock :singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock@4554617c
lazyDoubleLock1:singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock@4554617c
Process finished with exit code 0
结论:
- 单例只有一个实例
- 双重检查锁,线程安全
静态内部类
- 代码:
package singleton;
/**
* @author liouwb
* 单例模式 静态内部类
*/
public class SingletonInnerTest {
public static void main(String[] args) {
// 单例静态内部类
SingletonInner inner = SingletonInner.getInstance();
SingletonInner inner1 = SingletonInner.getInstance();
// 验证单例是否全局只有一个实例
System.out.println("正常获取的实例比较:" + (inner == inner1));
// 输出相应对象
System.out.println("inner :" + inner);
System.out.println("inner1:" + inner1);
}
/**
* 单例静态内部类
*/
static class SingletonInner {
private SingletonInner() {
}
private static class SingleTonHoler {
private static SingletonInner INSTANCE = new SingletonInner();
}
public static SingletonInner getInstance() {
return SingleTonHoler.INSTANCE;
}
}
}
- 输出结果:
正常获取的实例比较:true
inner :singleton.SingletonInnerTest$SingletonInner@4554617c
inner1:singleton.SingletonInnerTest$SingletonInner@4554617c
Process finished with exit code 0
结论:
- 输出结果为同一实例
- 静态内部类单例模式,线程安全
枚举单例
- 代码
package singleton;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @author liouwb
* 单例模式 枚举
*/
public class SingletonEnumTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 单例 枚举
SingletonEnum singletonEnum = SingletonEnum.getInstance();
SingletonEnum singletonEnum1 = SingletonEnum.getInstance();
// 验证单例是否全局只有一个实例
System.out.println("正常获取的实例比较:" + (singletonEnum == singletonEnum1));
// 输出相应对象
System.out.println("singletonEnum :" + singletonEnum.hashCode());
System.out.println("singletonEnum1:" + singletonEnum1.hashCode());
}
/**
* 枚举 单例
*/
enum SingletonEnum {
INSTANCE;
public static SingletonEnum getInstance() {
return INSTANCE;
}
}
}
- 输出结果:
正常获取的实例比较:true
singletonEnum :1163157884
singletonEnum1:1163157884
Process finished with exit code 0
结论:
- 输出结果为同一实例