概念介绍
一个类只有一个实例,且该类能自行创建这个实例的一种模式。
例如:多线程中的线程池、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、等常常被设计成单例。
特点
-
单例类只有一个实例对象
-
该单例对象必须由单例类自行创建
-
单例类对外提供一个访问该单例的全局访问点
优劣势
优势
-
在应用场景中,某类只要求生成一个对象的时候。
-
当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如数据库的连接池等。
-
当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
劣势
-
不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
-
由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
-
单例类的职责过重,在一定程度上违背了“单一职责原则”。
-
滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
实现单例模式的八种方式
-
1、饿汉式(静态常量)
-
2、饿汉式(静态代码块)
-
3、懒汉式(线程不安全)
-
4、懒汉式(线程安全,同步方法)
-
5、懒汉式(线程安全,同步代码块)
-
6、双重检查
-
7、静态内部类
-
8、枚举
类图
代码示例
饿汉式(静态常量)
/**
* @author yulecha
* @version 1.0.0
* @ClassName SingletonEH.java
* @Description 饿汉式
* @createTime 2019年10月17日 14:45:00
*/
public class SingletonEH {
/**
* 本类内部创建对象实例
*/
private final static SingletonEH instance = new SingletonEH();
/**
* 构造器私有化,防止外部通过 new 的方式创建对象
*/
private SingletonEH() {
}
/**
* 提供一个公有的静态方法,返回实例对昂
* @return
*/
public static SingletonEH getInstance() {
return instance;
}
}
/**
* @author yulecha
* @version 1.0.0
* @ClassName SingletonEHTest.java
* @Description 测试单例模式(饿汉式)
* @createTime 2019年10月17日 14:48:00
*/
public class SingletonEHTest {
@Test
public void getInstanceTest() {
SingletonEH eh1 = SingletonEH.getInstance();
SingletonEH eh2 = SingletonEH.getInstance();
// 测试通过(比较内存地址是否相同)
assertThat(eh1, equalTo(eh2));
// 测试通过(比较 hashCode 是否相同)
assertThat(eh1.hashCode(), equalTo(eh2.hashCode()));
}
}
懒汉式(线程不安全)
/**
* @author yulecha
* @version 1.0.0
* @ClassName SingletonLH.java
* @Description 懒汉式(线程不安全)
* @createTime 2019年10月17日 15:10:00
*/
public class SingletonLH {
/**
* 定义一个 SingletonLH 类型的属性 instance
*/
private static SingletonLH instance;
/**
* 构造器私有话,防止外部通过 new 的方式创建对象
*/
private SingletonLH() {
}
/**
* 提供一个公有的静态方法,当使用到该方法时,才去创建 instance
* @return
*/
public static SingletonLH getInstance() {
if (instance == null) {
instance = new SingletonLH();
}
return instance;
}
}
/**
* @author yulecha
* @version 1.0.0
* @ClassName SingletonLHTest.java
* @Description 单例模式测试(懒汉式)
* @createTime 2019年10月17日 15:14:00
*/
public class SingletonLHTest {
@Test
public void getInstanceTest() {
SingletonLH ln1 = SingletonLH.getInstance();
SingletonLH lh2 = SingletonLH.getInstance();
// 测试通过(比较内存地址是否相同)
assertThat(ln1, equalTo(lh2));
// 测试通过(比较 hashCode 是否相同)
assertThat(ln1.hashCode(), equalTo(lh2.hashCode()));
}
}
懒汉式(线程安全,同步方法)
/**
* @author yulecha
* @version 1.0.0
* @ClassName s.java
* @Description 懒汉式(线程安全)
* @createTime 2019年10月17日 15:21:00
*/
public class SingletonLH {
/**
* 定义一个 SingletonLH 类型的属性 instance
*/
private static SingletonLH instance;
/**
* 构造器私有话,防止外部通过 new 的方式创建对象
*/
private SingletonLH() {}
/**
* 提供一个公有的静态方法,当使用到该方法时,才去创建 instance
* 加了锁,
* @return
*/
public static synchronized SingletonLH getInstance() {
if (instance == null) {
instance = new SingletonLH();
}
return instance;
}
}
总结
单例模式大家都普遍很熟悉,实现起来也很简单。一般点的面试题要求就是手写单例模式,饿汉式和懒汉式均可,需要注意的是懒汉式线程是否安全。