什么是单例模式?
// 定义
Ensure a class has only one instance,and provide a global point of access to it.
确保某一个类只有一个实例,,而且自行实例化并向整个系统提供这个实例。
通用源码:
/**
* 单例模式通用源代码 - [ 饿汉式单例 ]
*
* Singleton 类为单例类,通过使用 private 的构造器确保了在一个应用中只产生一个实例,并且是自行实例化.
*
* @author wenlong
* @date 2019/05/25 23:25
*/
public class Singleton {
private static final Singleton SINGLETON = new Singleton();
private Singleton() {
}
public static Singleton getSingleton() {
return SINGLETON;
}
public static void doSomething() {
System.out.println("Do something!");
}
}
上述单例有的地方称为饿汉式单例。
下述这种被称为懒汉式单例:
/**
* 单例模式实现 - 懒汉式单例
*
* @author ***
* @date 2019/05/26 11:19
*/
public class Singleton2 {
private static Singleton2 singleton2 = null;
private Singleton2() {
// 私有构造器
}
public static synchronized Singleton2 getInstance() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
单例模式的扩展 - 有上限的多例模式
具体实现:
/**
* 有上限的多例模式 - 单例模式的扩展
*
* @author wenlong
* @date 2019/05/26 11:42
*/
public class LimitNumOfInstances {
// 定义最多能产生的实例数量
private static int maxNumOfInstances = 3;
/**
* 定义对象的私有属性
*/
private String name;
/**
* 定义容器,容纳所有的实例
*/
private static List<LimitNumOfInstances> limitNumOfInstancesList = new ArrayList<>();
/**
* 当前实例的编号
*/
private static int indexOfInstance = 0;
private LimitNumOfInstances() {
}
private LimitNumOfInstances(String name) {
this.name = name;
}
// 生成所有对象
static {
for (int i = 0;i < maxNumOfInstances;i++) {
limitNumOfInstancesList.add(new LimitNumOfInstances("实例-" + i));
}
}
public static LimitNumOfInstances getInstance() {
Random random = new Random();
// 随机获取一个实例
indexOfInstance = random.nextInt(maxNumOfInstances);
return limitNumOfInstancesList.get(indexOfInstance);
}
/**
* 验证
*/
public void getInfo() {
System.out.println(this.name);
}
}
验证:
/**
* @author wenlong
* @date 2019/05/26 12:17
*/
public class Test {
public static void main(String[] args) {
for (int i = 0;i < 5;i++) {
LimitNumOfInstances randonOne = LimitNumOfInstances.getInstance();
randonOne.getInfo();
}
}
}
测试结果:
单例的其他实现方式:
1.饿汉式(静态代码块)
/**
* 单例模式 - 饿汉式(静态代码块)
*
* @author wenlong
* @date 2019/05/26 16:27
*/
public class Singleton3 {
private static Singleton3 instance;
static {
instance = new Singleton3();
}
private Singleton3() {}
public static Singleton3 getInstance() {
return instance;
}
}
2.懒汉式(线程不安全)
/**
* 单例模式实现 - 懒汉式单例 - 线程不安全
*
* @author ***
* @date 2019/05/26 11:19
*/
public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2() {
// 私有构造器
}
public static Singleton2 getInstance() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
3.懒汉式(线程安全 - 同步代码块)
/**
* 懒汉式单例 - 同步代码块
*
* @author wenlong
* @date 2019/05/26 16:51
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {}
public static Singleton4 getInstance() {
if (instance == null) {
synchronized(Singleton4.class) {
instance = new Singleton4();
}
}
return instance;
}
}
该写法虽然是线程安全的,但是在多线程环境下还是有可能产生多个实例。不可用。
4.懒汉式 - 双重检查【推荐使用】
/**
* 单例模式 - 懒汉式 - 同步代码块 - 双重检查
* 优点:线程安全;延迟加载;效率较高。
*
* @author wenlong
* @date 2019/05/26 17:01
*/
public class Singleton5 {
private static volatile Singleton5 instance;
private Singleton5() {}
public Singleton5 getInstance() {
if (instance == null) {
synchronized(Singleton5.class) {
if (instance == null) {
instance = new Singleton5();
}
}
}
return instance;
}
}
5.静态内部类【推荐使用】
/**
* 单例模式 - 静态内部类
*
* @author wenlong
* @date 2019/05/26 17:10
*/
public class Singleton6 {
private Singleton6() {}
/**
* 静态内部类
*/
private static class SingletonInstance {
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance() {
return SingletonInstance.INSTANCE;
}
}
这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才会装载 SingletonInstance 类,从而完成 Singleton 的实例化。
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
优点:避免了线程不安全,延迟加载,效率高。
6.单例模式 - 枚举【推荐使用】
/**
* 单例模式 - 枚举
*
* @author wenlong
*/
public enum Singleton7 {
/**
* 单例模式 - 枚举
*/
INSTANCE;
public void whateverMethod() {
System.out.println("哈哈哈");
}
}