单例设计模式
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
如下:
1 public class Person(){
2 // 默认生成一个公共的空参构造方法
3 }
4 // 测试类
5 public static void main(String[] args) {
6 // 正常情况下一个类可以创建多个对象
7 Person p1 = new Person();
8 Person p2 = new Person();
9 Person p3 = new Person();
10 // ...
11 }
介绍
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
优缺点:
优点:
- 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
- 2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
例设计模式的类型
根据实例化对象的时机单例设计模式又分为以下两种:
-
饿汉单例设计模式
-
懒汉单例设计模式
1、懒汉式,线程安全
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
什么是懒汉模式:通俗来说懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才实例化出对象。不着急,故称为“懒汉模式”。
1 public class Person {
2 // 懒汉式单例: 不着急,只要当你调用了getInstance静态方法获取对象的时候,就创建,其他时候不创建
3 // 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
4 private Person(){
5
6 }
7
8 // 2. 在该类内部产生一个唯一的实例化对象
9 private static Person p ;// 默认值为null
10
11 // 3. 定义一个静态方法返回这个唯一对象。
12 public static synchronized Person getInstance(){
13 // 创建Person类的唯一对象
14 // 判断一下,如果p这个成语变量的值为null,就创建,不为null,说明该对象已经创建了,直接返回即可
15 if (p == null){
16 p = new Person();
17 }
18 return p;
19 }
20
21 // ...
22 }
23
24 public class Test {
25 public static void main(String[] args) {
26 Person p1 = Person.getInstance();
27 Person p2 = Person.getInstance();
28 Person p3 = Person.getInstance();
29
30 System.out.println(p1);
31 System.out.println(p2);
32 System.out.println(p3);
33
34
35 }
36 }
注意:懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态,所以加上关键字:synchronized,保证其同步安全。
2、饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
public class Person {
// 使用饿汉式单例设计模式: 比较着急,不管要不要获取我这个类的对象,先创建了该对象再说
// 1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
private Person(){
}
// 2. 在该类内部产生一个唯一的实例化对象
private static final Person p = new Person();
// 3. 定义一个静态方法返回这个唯一对象。
public static Person getInstance(){
return p;
}
// ....
}
public class Test {
public static void main(String[] args) {
Person p1 = Person.getInstance();
Person p2 = Person.getInstance();
Person p3 = Person.getInstance();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
}
}