网站开发公司怎么选择,jsp网站开发的mvc,自己怎么建h5商城网站,沈阳做网站哪个好一、单例模式的定义 定义#xff1a; 确保一个类只有一个实例#xff0c;并提供该实例的全局访问点。
这样做的好处是#xff1a;有些实例#xff0c;全局只需要一个就够了#xff0c;使用单例模式就可以避免一个全局使用的类#xff0c;频繁的创建与销毁#xff0c;耗…一、单例模式的定义 定义 确保一个类只有一个实例并提供该实例的全局访问点。
这样做的好处是有些实例全局只需要一个就够了使用单例模式就可以避免一个全局使用的类频繁的创建与销毁耗费系统资源。
二、单例模式的设计要素 一个私有构造函数 确保只能单例类自己创建实例 一个私有静态变量 确保只有一个实例 一个公有静态函数 给使用者提供调用方法 简单来说就是单例类的构造方法不让其他人修改和使用并且单例类自己只创建一个实例这个实例其他人也无法修改和直接使用然后单例类提供一个调用方法想用这个实例只能调用。这样就确保了全局只创建了一次实例。
三、单例模式的6种实现及各实现的优缺点 一懒汉式线程不安全 实现
public class Singleton {private static Singleton uniqueInstance;private Singleton() {}public static Singleton getUniqueInstance() {if (uniqueInstance null) {uniqueInstance new Singleton();}return uniqueInstance;}
}说明 先不创建实例当第一次被调用时再创建实例所以被称为懒汉式。
优点 延迟了实例化如果不需要使用该类就不会被实例化节约了系统资源。
缺点 线程不安全多线程环境下如果多个线程同时进入了 if (uniqueInstance null) 若此时还未实例化也就是uniqueInstance null那么就会有多个线程执行 uniqueInstance new Singleton(); 就会实例化多个实例
二饿汉式线程安全 实现
public class Singleton {private static Singleton uniqueInstance new Singleton();private Singleton() {}public static Singleton getUniqueInstance() {return uniqueInstance;}}说明 先不管需不需要使用这个实例直接先实例化好实例 (饿死鬼一样所以称为饿汉式)然后当需要使用的时候直接调方法就可以使用了。
优点 提前实例化好了一个实例避免了线程不安全问题的出现。
缺点 直接实例化好了实例不再延迟实例化若系统没有使用这个实例或者系统运行很久之后才需要使用这个实例都会操作系统的资源浪费。
三懒汉式线程安全 实现
public class Singleton {private static Singleton uniqueInstance;private static singleton() {}private static synchronized Singleton getUinqueInstance() {if (uniqueInstance null) {uniqueInstance new Singleton();}return uniqueInstance;}}说明 实现和 线程不安全的懒汉式 几乎一样唯一不同的点是在get方法上 加了一把 锁。如此一来多个线程访问每次只有拿到锁的的线程能够进入该方法避免了多线程不安全问题的出现。
优点 延迟实例化节约了资源并且是线程安全的。
缺点 虽然解决了线程安全问题但是性能降低了。因为即使实例已经实例化了既后续不会再出现线程安全问题了但是锁还在每次还是只能拿到锁的线程进入该方法会使线程阻塞等待时间过长。
四双重检查锁实现线程安全 实现
public class Singleton {private volatile static Singleton uniqueInstance;private Singleton() {}public static Singleton getUniqueInstance() {if (uniqueInstance null) {synchronized (Singleton.class) {if (uniqueInstance null) {uniqueInstance new Singleton();}}}return uniqueInstance;}
}说明: 双重检查数相当于是改进了 线程安全的懒汉式。线程安全的懒汉式 的缺点是性能降低了造成的原因是因为即使实例已经实例化依然每次都会有锁。而现在我们将锁的位置变了并且多加了一个检查。 也就是先判断实例是否已经存在若已经存在了则不会执行判断方法内的有锁方法了。 而如果还没有实例化的时候多个线程进去了也没有事因为里面的方法有锁只会让一个线程进入最内层方法并实例化实例。如此一来最多最多也就是第一次实例化的时候会有线程阻塞的情况后续便不会再有线程阻塞的问题。
为什么使用 volatile 关键字修饰了 uniqueInstance 实例变量
uniqueInstance new Singleton(); 这段代码执行时分为三步
为 uniqueInstance 分配内存空间 初始化 uniqueInstance 将 uniqueInstance 指向分配的内存地址 正常的执行顺序当然是 123 但是由于 JVM 具有指令重排的特性执行顺序有可能变成 132。 单线程环境时指令重排并没有什么问题多线程环境时会导致有些线程可能会获取到还没初始化的实例。 例如线程A 只执行了 1 和 3 此时线程B来调用 getUniqueInstance()发现 uniqueInstance 不为空便获取 uniqueInstance 实例但是其实此时的 uniqueInstance 还没有初始化。
解决办法就是加一个 volatile 关键字修饰 uniqueInstance volatile 会禁止 JVM 的指令重排就可以保证多线程环境下的安全运行。
优点 延迟实例化节约了资源线程安全并且相对于 线程安全的懒汉式性能提高了。
缺点 volatile 关键字对性能也有一些影响。
五静态内部类实现线程安全 实现
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}public static Singleton getUniqueInstance() {return SingletonHolder.INSTANCE;}}说明 首先当外部类 Singleton 被加载时静态内部类 SingletonHolder 并没有被加载进内存。当调用 getUniqueInstance() 方法时会运行 return SingletonHolder.INSTANCE; 触发了 SingletonHolder.INSTANCE 此时静态内部类 SingletonHolder 才会被加载进内存并且初始化 INSTANCE 实例而且 JVM 会确保 INSTANCE 只被实例化一次。
优点 延迟实例化节约了资源且线程安全性能也提高了。
六枚举类实现线程安全 实现
public enum Singleton {INSTANCE;
//添加自己需要的操作public void doSomeThing() {}}说明 默认枚举实例的创建就是线程安全的且在任何情况下都是单例。
优点 写法简单线程安全天然防止反射和反序列化调用。
防止反序列化序列化把java对象转换为字节序列的过程 反序列化 通过这些字节序列在内存中新建java对象的过程 说明 反序列化 将一个单例实例对象写到磁盘再读回来从而获得了一个新的实例。 我们要防止反序列化避免得到多个实例。 枚举类天然防止反序列化。 其他单例模式 可以通过 重写 readResolve() 方法从而防止反序列化使实例唯一重写 readResolve() : private Object readResolve() throws ObjectStreamException{ return singleton; } 四、单例模式的应用场景 应用场景举例
网站计数器。 应用程序的日志应用。 Web项目中的配置对象的读取。 数据库连接池。 多线程池。 … 使用场景总结
频繁实例化然后又销毁的对象使用单例模式可以提高性能。 经常使用的对象但实例化时耗费时间或者资源多如数据库连接池使用单例模式可以提高性能降低资源损坏。 使用线程池之类的控制资源时使用单例模式可以方便资源之间的通信。