java之单例模式
什么是单例模式?
保证一个了类仅有一个实例,并提供一个访问它的全局访问点。
单例模式的应用场景?
1.网站的计数器,一般也是采用单例模式实现,否则难以同步;
2.Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源;
3.数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源;
4.多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
单例的优缺点?
优点:
提供了对唯一实例的受控访问;
由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能;
避免对共享资源的多重占用
缺点:
不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态;
由于单利模式中没有抽象层,因此单例类的扩展有很大的困难;
单例类的职责过重,在一定程度上违背了“单一职责原则”。
单例的创建方式
1. 饿汉式
类初始化时,会立即加载该对象,线程安全,效率高。
/**
* @Author 刘翊扬
* @Version 1.0
*/
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return instance;
}
}
验证:
public class Main {
public static void main(String[] args) {
SingletonHungry instance1 = SingletonHungry.getInstance();
SingletonHungry instance2 = SingletonHungry.getInstance();
System.out.println(instance1 == instance2); // 结果是true
}
}
优点:仅实例化一次,线程是安全的。获取实例的速度快
缺点:类加载的时候立即实例化对象,可能实例化的对象不会被使用,造成内存的浪费。
2. 使用静态代码块
**
* @author 刘翊扬
*/
public class HungrySingleton2 {
private static HungrySingleton2 instance = null;
private HungrySingleton2() {
}
static {
instance = new HungrySingleton2();
}
private HungrySingleton2() {
}
public static HungrySingleton2 getInstance() {
return instance;
}
}
3. 懒汉式
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
优点:在使用的时候,创建对象,节省系统资源
缺点:
如果获取实例时,初始化的工作量较多,加载速度会变慢,影响系统系能
每次获取对象,都要进行非空检查,系统开销大
非线程安全,当有多个线程同时调用 getInstance()方法,时,会有线程安全问题,可能导致创建多个对象
4. 静态内部类
/**
* @Author 刘翊扬
* @Version 1.0
*/
public class SingletonDemo03 {
private SingletonDemo03() {
}
public static class SingletonClassInstance {
private static final SingletonDemo03 instance = new SingletonDemo03();
}
public static SingletonDemo03 getInstance() {
return SingletonClassInstance.instance;
}
}
优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。
劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象。
5. 使用枚举
枚举本身就是单例的,一般在项目中定义常量。
例如:
/**
* @Author 刘翊扬
* @Version 1.0
*/
public enum ResultCode {
SUCCESS(200, "SUCCESS"),
ERROR(500, "ERROR");
private Integer code;
private String msg;
ResultCode(Integer code, String msg