正常情况下一个类可以创建多个对象
public static void main(String[] args) {
// 正常情况下一个类可以创建多个对象
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
但是有些时候的某些类, 我们希望只能创建单一的一个对象, 这时候我们需要使用到单例设计模式, 下面我们来介绍一下单例设计模式.
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例设计模式的作用
单例设计模式的实现步骤
饿汉单例设计模式就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。
代码如下:
public class Singleton {
// 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
private Singleton() {}
// 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
private static final Singleton instance = new Singleton();
// 3.定义一个静态方法返回这个唯一对象。
public static Singleton getInstance() {
return instance;
}
}
懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才例化出对象。不着急,故称为“懒汉模式”。
package com.itheima._01single.demo02;
/**
*
* 懒汉式
* 懒: 上来不着急创建对象, 什么时候用, 什么时候创建
*
*/
public class Singleton {
// 1. 私有构造
private Singleton() {}
// 2. 只声明本类的引用, 后面不创建对象
private static Singleton instance;
// 3. 提供公共的用来获取本类对象的方法
public static Singleton getInstance() {
// 判断: 如果instance为null => 创建对象
if (instance == null) {
// 为了看到效果, 所以让线程睡一会
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 什么时候用, 什么时候创建
instance = new Singleton();
}
// 如果instance不为null, 直接返回
return instance;
}
}
结论: 在实际开发中不要使用这种方式.
私有构造方法
类的内部创建对象
对外暴露一个用于获取对象的静态同步方法
判断对象是否为空
如果为空就实例化
返回当前对象
package com.itheima._01single.demo03;
/**
* 懒汉式 - 同步方法
*/
public class Singleton {
// 1. 私有构造
private Singleton() {
}
// 2. 声明引用
private static Singleton instance; // 实例
// 3. 获取对象的方法
public static synchronized Singleton getInstance() {
// 判断, 如果为null, 创建对象
if (instance == null) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton();
}
// 如果不为null, 直接返回
return instance;
}
}
优点: 解决了多线程中创建多个对象的问题
缺点: 效率太低, 每次执行都要进入同步方法.
总结: 实际开发中不推荐使用
私有构造方法
类的内部创建对象
对外暴露一个用于获取对象的静态方法
判断对象是否为空
在同步代码块中进行判断, 如果为空就实例化
返回当前对象
package com.itheima._01single.demo04;
/**
*
* 懒汉式 - 同步代码块
*
* 这种实现方式是有问题的, 我要用这种方式给大家引出最终的BOSS
*
* 刚才使用同步方法的时候, 可以保证只创建一个对象, 但是每一次都要先获取锁
*
* 1. 不每一次上来就直接先获取锁
* 2. 等判断完为null, 再获取锁, 创建对象
*
*/
public class Singleton {
// 1. 私有构造
private Singleton() {}
// 2. 声明引用
private static Singleton instance;
// 3. 公共方法
// 把获取锁对象的时机延后, 且不满足条不会获取锁(减少了获取锁的次数)
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
实际开发中不能使用
package com.itheima._01single.demo05;
/**
*
* 双重检查
*
* 1. 两个if(instance == null) 的判断
* 2. 加上volatile关键字, 保证共享数据可可见性
*
*/
public class Singleton {
// 1. 私有构造
private Singleton() {}
// 2. 声明引用
private static volatile Singleton instance;
// 3. 提供获取对象的方法
public static Singleton getInstance() {
// 如果对象不存在
if (instance == null) {
// 线程1, 判断是null || 线程2, 判断是null
// 同步锁
// 问题: 多线程中有可能创建多个对象
synchronized (Singleton.class) {
if (instance == null) {
// 创建对象
instance = new Singleton();
}
}
}
return instance;
}
}
总结: 实际开发中, 推荐使用这种单例设计模式
多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。
1.创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
2.在类中定义该类被创建的总数量
3.在类中定义存放类实例的list集合
4.在类中提供静态代码块,在静态代码块中创建类的实例
5.提供获取类实例的静态方法
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Multition {
// 定义该类被创建的总数量
private static final int maxCount = 3;
// 定义存放类实例的list集合
private static List instanceList = new ArrayList();
// 构造方法私有化,不允许外界创建本类对象
private Multition() {
}
static {
// 创建本类的多个实例,并存放到list集合中
for (int i = 0; i < maxCount; i++) {
Multition multition = new Multition();
instanceList.add(multition);
}
}
// 给外界提供一个获取类对象的方法
public static Multition getMultition(){
Random random = new Random();
// 生成一个随机数
int i = random.nextInt(maxCount);
// 从list集合中随机取出一个进行使用
return (Multition)instanceList.get(i);
}
}
public static void main(String[] args) {
// 编写一个循环从中获取类对象
for (int i = 0; i < 10; i++) {
Multition multition = Multition.getMultition();
System.out.println(multition);
}
}
多例模式可以保证系统中一个类有固定个数的实例, 在实现需求的基础上, 能够提高实例的复用性.