关于单例模式,话不多说,即程序运行时无论New了多少次,即内存中只有一个实例对象。即对象的HasHCode一致。

单例模式的两大类

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

1、饿汉模式(即加载时就创建对象)

  -1、直接实例化饿汉模式

  -2、静态代码块饿汉模式(即需要加载初始化配置的时候适用)

  -3、枚举方式

2、懒汉式(延迟加载)

  -1、单线程安全下的懒汉

  -2、多线程安全下的懒汉

  -3、静态内部类的懒汉(安全)

  

  1、直接实例化饿汉模式

  

package com.single; public class Singleton { private static final Singleton SI=new Singleton(); private Singleton(){ } public static Singleton getsingleton(){ return SI; } }

 

  单例模式必须保证自行创建,并且内部提供一个静态变量来保存这个唯一的对象,构造器私有化,即其他类内部中无法直接New当前的单例类,还需要提供一个对外获取实例的方法

  当前模式在加载类的字节码的时候当前类的实例就立即会被创建

 

  2、静态代码块饿汉模式(即需要加载初始化配置的时候适用)

  

 1 public class Singleton2 {  2 
 3     private static final Singleton2 SI;  4 
 5     private String name;  6     static {  7         Properties properties=new Properties();  8         try {  9      
10             properties.load(Singleton2.class.getClassLoader().getResourceAsStream("db.properties")); 11             String name = properties.getProperty("name"); 12             SI=new Singleton2(name); 13         } catch (IOException e) { 14             throw new RuntimeException(e); 15  } 16 
17  } 18 
19     private Singleton2(String name){ 20         this.name=name; 21  } 22 
23     public static Singleton2 getsingleton(){ 24         return SI; 25     }

 当我们需要在类创建的时候初始化参数,并且加载某些配置文件的时候可以使用 静态代码块的方式,在创建实例的时候通过构造器来完成相关参数的初始化。

 3.枚举方式的单例,自JDK1.5之后,首先枚举类和普通类的区别是什么?

使用enum定义的枚举类默认继承了java.lang.Enum类

枚举类的构造器只能使用private

枚举类的每个实例必须在枚举类中显示的列出(,分隔   ;结尾) 列出的实例系统会自动添加public static final修饰

所有的枚举类都定义了一个values方法,该方法可以很方便的遍历所有的枚举值

可以在switch表达式使用枚举类对象作为表达式,case子句可以直接使用枚举的名字,无需添加枚举类作为限定

枚举类对象的属性不能更改,所以要用private final修饰

枚举类对象要在构造器中被赋值
---------------------
作者:weirdowang
来源:CSDN
原文:https://blog.csdn.net/weirdowang/article/details/79970673

package com.single; /* 枚举方式的单例 */
public enum SingEnum { SING; SingEnum(){ } public void info(){ System.out.println("显示"); } }

  是不是很简洁呢? 确实如此,单例模式下 枚举方式的单例是最简洁的

  二、懒汉模式

 

  1、单线程安全下的懒汉

  

package com.single2; /* 懒汉模式 */ public class Singleton { private static Singleton singleton; private Singleton(){ System.out.println("创建"); } public static Singleton getSingleton(){ if (singleton==null){ singleton=new Singleton(); } return singleton; } }

 

  我们可以看出无论怎么样,当前的懒汉都是在调用的时候才被加载创建的,但是它只是在单线程的情况下是安全的为什么呢? 现在有一个需求即多个线程对这个 单例进行访问构建对象,在构建对象的时候使当前线程短暂的休眠一下

package com.single2; /* 懒汉模式测试线程不安全 */
public class Singleton2 { private static Singleton2 singleton; private Singleton2(){ System.out.println("创建"); } public static Singleton2 getSingleton() throws InterruptedException { if (singleton==null){ Thread.sleep(100); singleton=new Singleton2(); } return singleton; } }

测试代码如下:

  

  /* 懒汉模式下的多线程不安全 */
    public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { try { Singleton2 singleton1 = Singleton2.getSingleton(); System.out.println(singleton1); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { Singleton2 singleton2 = Singleton2.getSingleton(); System.out.println(singleton2); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); thread2.start(); }

  经过测试,多线程情况下这种是不安全的 为什么呢?  第一个线程进入 进去之后, 线程休眠100ms 在此期间,第二个线程也开始进去到了创建的方法,由于当前第一个线程正在休眠,所以当前单例为null ,然后第一个线程休眠结束,创建第一个对象,此后第二个线程还在if中,也相继创建对象,此时便构造成了线程不安全的懒汉单例

  2、线程安全的懒汉单例(双端检索)

package com.single2; /* 懒汉模式 双端检索,避免了多次线程等待 */
public class Singleton4 { private static Singleton4 singleton4; private Singleton4() { } public static Singleton4 getSingleton4() { if (singleton4 == null) { synchronized (Singleton4.class) { if (singleton4 == null) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } singleton4 = new Singleton4(); } } } return singleton4; } }
使用synchronized 保证当前只能有一个线程进入 ,并且在外再次进行判断 若当前的单例已经被创建过了,避免了再次加锁,直接返回 
3、静态内部类的懒汉单例:(线程安全的)
package com.single2; public class Singleton5 { private Singleton5(){ } private static class demo{ private static final Singleton5 SINGLETON_5=new Singleton5(); } public static Singleton5 singleton5(){ return demo.SINGLETON_5; } }

也是懒汉模式最简单的单例实现,静态内部类不会随着外部类的初始化而初始化,并且内部类具有自己的类加载器,是安全的

如上便是单例模式的六种创建方式,欢迎大牛指正,源码放到群里了  另外也欢迎各位朋友们一起学习交流, qq群:956809929

 

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄