单例模式的简单理解

Posted CppTeam

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式的简单理解相关的知识,希望对你有一定的参考价值。

单例模式

定义:在应用单例模式时,一个类只能有一个对象。这个对象只能自行创建,可以全局有效。

  • 饿汉式单例
  • 懒汉式单例
  • 静态内部类
  • 枚举方式

饿汉式单例

饿汉式单例,顾名思义。类加载时就创建一个实例,调用方法时提供实例。它的线程安全由JVM提供。缺点就是初始化时,可能会因为要分配多个实例,占用较多的资源。

上代码

/** * 饿汉式单例 */public class Hungry {

//可能浪费空间 private byte[] data1 =new byte[1024*1024]; private byte[] data2 =new byte[1024*1024];
// 构造反法私有化,不允许外部访问,确保自行创建实例 private Hungry(){
}
// 创建唯一的静态实例,确保唯一性 private final static Hungry HUNGRY =new Hungry();
// 提供一个获取实例的公有方法,确保全局有效 public static Hungry getInstance(){ return HUNGRY; }
}

懒汉式单例

懒汉式单例,顾名思义,比较“懒”,延迟加载,类记载时不创建实例,而是先声明一个实例,调用方法时提供实例

/** * 懒汉式单例 */public class LazyMan {
private LazyMan(){
synchronized (LazyMan.class){ //相当于是第三层锁 if (lazyMan!=null){ throw new RuntimeException("不要试图使用反射破化单例"); } }
System.out.println(Thread.currentThread().getName()+"ok"); }
/**双重检测锁+原子性操作 * */ //声明一个实例 private volatile static LazyMan lazyMan; //第二层锁 //volatile 修饰符阻止了变量访问前后的指令重排,保证指令的执行顺序

public static LazyMan getInstance(){ if (lazyMan==null){ //第一层检测 synchronized (LazyMan.class){ //第一层锁 if (lazyMan==null){ //第二层检测 lazyMan=new LazyMan(); //不是一个原子操作 /** * instance = new DoubleCheckIdGenerator(); 并不是一个原子操作, * 1. 分配内存空间 * 2. 执行构造方法 * 3. 把这个对象指向这个空间 * 在创建的过程中,因为JVM的优化,2和3这两个步骤是可以发生指令重排的,这就导致了多线程情况下,会返回没经过初始化的对象,加个volatile既可以解决这个问题 */ } } } return lazyMan; }

整个代码的实现思路:先声明一个带volatile修饰符的实例,当这个实例是空的时候,给这个实例上把锁 ,保证只有一个线程进入。当第一个线程结束后可能还会由进程进来,创建多个对象,造成线程不安全,所以要进行第二次检测。

静态内部类

静态内部类思想的精妙之处在于“静态内部类”,什么意思呢?

静态内部类定义的实例属于类,而不是属于某个对象。当加载外部类Holder时不会创建内部类InnerClass的实例对象,只有调用getInstance()方法时才会创建HOLDEE实例对象。HOLDER 的线程安全由JVM保证。


/** * 静态内部类 */public class Holder {
private Holder(){
}
public static Holder getInstance(){ return InnerClass.HOLDER; } public static class InnerClass{
private static final Holder HOLDER=new Holder(); }}

枚举方式

枚举方式实现的单例模式不仅能避免多线程同步的问题,也可以防止反射的破坏。

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;
/** * 枚举类型 * enum是什么。本身也是一个class类 */public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() { return INSTANCE; }} class Test{ public static void main(String[] args) throws NoSuchMethodException,IllegalAccessException, InvocationTargetException,InstantiationException { EnumSingle instance = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class); declaredConstructor.setAccessible(true); EnumSingle instance1 = declaredConstructor.newInstance();
//输出测试 System.out.println(instance); System.out.println(instance1); } }




以上是关于单例模式的简单理解的主要内容,如果未能解决你的问题,请参考以下文章

单例模式的简单理解

设计模式的简单理解——单例模式

Java:java学习笔记之Java单例模式的简单理解和使用

Java:java学习笔记之Java单例模式的简单理解和使用

单例模式,这个面试题真那么简单吗?

深入理解单例模式