哪个网站做的简历比较好,永久3e39cosvv457,学校网站建设专业公司,古镇建设网站虽然写了很多年代码#xff0c;但是说真的对设计模式不是很熟练#xff0c;虽然平时也会用到一些#xff0c;但是都没有深入研究过#xff0c;所以趁现在有空练下手
这章主要讲单例模式#xff0c;也是最简单的一种模式#xff0c;但是因为spring中bean的广泛应用#…虽然写了很多年代码但是说真的对设计模式不是很熟练虽然平时也会用到一些但是都没有深入研究过所以趁现在有空练下手
这章主要讲单例模式也是最简单的一种模式但是因为spring中bean的广泛应用所以现在单例模式在应用中其实很少会手动实现 在Spring中默认情况下Bean 是单例的这意味着 Spring 容器会在第一次请求该 Bean 时创建一个实例并且在整个应用程序的生命周期中保持该实例的单一性。换句话说每次从 Spring 容器中请求相同的 Bean 时都会得到相同的实例。 单例模式是一种常见的设计模式适用于以下情况 1.资源共享当系统中需要共享某个资源如数据库连接池、线程池、配置信息等的时候可以使用单例模式确保全局只有一个实例避免资源的重复创建和浪费。 2.对象缓存在需要频繁创建和销毁对象的情况下可以使用单例模式将对象缓存起来提高性能。 3.线程池线程池通常被设计为单例以确保在整个应用程序中只有一个线程池实例用于管理线程的生命周期和执行任务。 4.日志对象在系统中使用单例模式创建日志对象可以确保所有的日志信息被统一记录避免出现混乱的日志信息。 5.配置文件对象将系统中的配置信息封装到单例对象中可以方便地进行读取和修改。 6.对话框、窗口等界面组件在图形用户界面GUI程序中通常只需要一个对话框或窗口实例可以使用单例模式确保全局只有一个实例。 7.管理器类例如线程管理器、事件管理器等这些管理器类通常被设计为单例以便在整个系统中统一管理资源和事件。 总之任何需要在系统中全局唯一存在的对象且需要被频繁访问和共享的情况下都可以考虑使用单例模式。 首先是最简单实用的饿汉模式 优点 1.线程安全 饿汉模式在类加载时就创建实例并且实例是静态的 final 变量因此在多线程环境下是线程安全的不需要额外的线程同步控制。 2.简单易用 饿汉模式的实现非常简单通过静态变量初始化的方式就可以保证实例的唯一性和全局可访问性不需要复杂的代码结构。 3.无需考虑懒加载和线程安全问题 由于实例是在类加载时就创建好的所以不需要考虑懒加载和线程安全问题避免了相关的复杂性。 4.性能较好 因为实例是在类加载时就创建好的所以在获取实例时无需进行额外的判断和同步操作性能较好。 缺点 1.资源浪费 饿汉模式在应用程序启动时就创建实例并且实例是在整个应用程序生命周期内存在的可能会导致资源的浪费。特别是如果实例占用大量资源或者需要较长时间进行初始化可能会影响应用程序的启动速度。 2.不支持延迟加载 饿汉模式不支持延迟加载因为实例是在类加载时就创建好的无法根据需要进行延迟加载。 3.可能导致类加载较慢 如果一个类的实例创建比较耗时那么在类加载时就会导致类加载较慢影响整个应用程序的启动速度。 综上所述饿汉模式适用于对性能要求较高且实例创建比较简单且资源消耗较小的情况下。但是需要注意可能存在的资源浪费问题特别是对于大型对象或者需要耗时初始化的实例。 直接上代码建议使用
public class EagerSingleton {// 在类加载时就创建实例并初始化为静态变量private static final EagerSingleton instance new EagerSingleton();// 私有化构造方法防止外部实例化private EagerSingleton() {}// 获取单例实例的方法public static EagerSingleton getInstance() {try {// 模拟处理业务逻辑耗时Thread.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return instance;}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(EagerSingleton.getInstance().hashCode());}).start();}}
}执行一下 可以看到hashCode都是一样的这里有人可能会说hashCode一样并不代表对象一样我只能说你的确是对的但这不在本章讲解范围内 然后我们再来看一下懒汉模式 优点 1.延迟加载Lazy Loading 懒汉模式在首次访问时才会创建实例避免了在程序启动时就创建对象实例节省了内存和系统资源。 2.节省资源 因为实例是在需要时才创建的所以在大部分情况下不会占用额外的资源。 3.线程安全问题相对简单 在单线程环境下懒汉模式不需要额外的线程同步机制来保证线程安全实现简单。 缺点 1.线程安全性问题 在多线程环境下懒汉模式可能存在线程安全问题。当多个线程同时调用 getInstance() 方法时如果没有进行额外的线程同步处理可能会导致创建多个实例。 2.性能问题 在并发环境下由于需要额外的线程同步控制懒汉模式的性能可能会受到一定影响。例如使用双重检查锁Double-Checked Locking来确保线程安全性会增加额外的开销。 3.可能存在反序列化问题 当类实现了 Serializable 接口并且对象被序列化然后再反序列化时如果没有正确地处理单例对象可能会破坏单例的约束导致出现多个实例。 4.不适用于高并发场景 在高并发场景下频繁调用 getInstance() 方法可能会导致性能瓶颈因为所有线程都需要竞争同一个锁来获取实例。 综上所述懒汉模式适用于单线程环境或者对性能要求不是非常高的场景但在多线程环境下需要特别注意线程安全性问题并且需要针对性能做出权衡。 直接上代码不建议使用
public class EagerSingleton {// 在类加载时就创建实例并初始化为静态变量private static final EagerSingleton instance new EagerSingleton();// 私有化构造方法防止外部实例化private EagerSingleton() {}// 获取单例实例的方法public static EagerSingleton getInstance() {try {// 模拟处理业务逻辑耗时Thread.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return instance;}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(EagerSingleton.getInstance().hashCode());}).start();}}
}执行一下 发现没有hashCode都不一样虽然hashCode相同不能证明对象是同一个但是hashCode不相同肯定不是同一个对象这说明其实是线程不安全的因此这种写法其实是被淘汰了的 上面的那种写法虽然不推荐使用但是提供了一种思路就是只在需要的时候才加载其主要目的还是为了节省资源现在的硬件其实都很强大这点资源省不省问题其实不大这也让我想起了很多年前我刚入行还在写C当时问我师父说这个指针要是忘了释放怎么办他跟我说没关系的现在电脑都很牛逼这点资源浪费根本影响不了什么
好了下面我们来完善一下懒汉模式最简单的方法就是使用synchronized关键字来保证线程的安全当然同时也就伴随着性能的损耗不推荐使用 这里直接用synchronized关键字锁整个方法
public class LazySingleton {// 注意volatile关键字是必须的防止指令重排序private static volatile LazySingleton instance;// 私有化构造方法防止外部实例化private LazySingleton() {}// 获取单例实例的方法public static synchronized LazySingleton getInstance() {// 在第一次调用时才创建实例if (instance null) {try {// 模拟处理业务逻辑耗时Thread.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}instance new LazySingleton();}return instance;}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(LazySingleton.getInstance().hashCode());}).start();}}
}执行一下 上面那个示例虽然保证了一个实例但是性能上还是不如意如是再优化一下就出现了下面这种不是很推荐因为看起来很复杂 这里只在需要的地方加synchronized就不再锁整个方法性能上提示了一丢丢注意这里其实是双重判断的懒汉模式还有一个只有一层判断因为和一开始的那个一样存在线程安全问题这里不做展示
public class LazySingleton {// 注意volatile关键字是必须的防止指令重排序private static volatile LazySingleton instance;// 私有化构造方法防止外部实例化private LazySingleton() {}// 获取单例实例的方法public static LazySingleton getInstance() {// 在第一次调用时才创建实例if (instance null) {synchronized (LazySingleton.class) {// 注意这里使用的是双重判断防止多线程并发时重复创建实例// 如果不加下面这个判断多线程并发时可能会创建多个实例if (instance null) {try {// 模拟处理业务逻辑耗时Thread.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}instance new LazySingleton();}}}return instance;}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(LazySingleton.getInstance().hashCode());}).start();}}
}通过比较可以发现饿汉模式是不管需不需要都会创建一个实例有点浪费资源然后在程序启动的时候会拖慢一点速度。懒汉模式虽然是在需要的时候才创建实例但是因为使用了synchronized关键字所以在使用的时候也会有性能问题。虽然问题都不大但是有些完美主义可能就接受不了所以下面我们再优化一下。
直接上代码建议使用目前来看应该是最完美的实现方式唯一的缺点就是不能反序列化 由于静态内部类只有在被使用的时候才会被加载所以单例实例的创建会延迟到 getInstance() 方法被调用的时候。而且由于类加载过程是线程安全的所以这种方式也是线程安全的。
public class Singleton {// 私有化构造方法防止外部实例化private Singleton() {}// 静态内部类持有单例实例private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}// 获取单例实例的方法public static Singleton getInstance() {try {// 模拟处理业务逻辑耗时Thread.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return SingletonHolder.INSTANCE;}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(Singleton.getInstance().hashCode());}).start();}}
}执行一下 那能不能写一个更完美的让它能反序列化呢答案当然是可以的 直接上代码虽然看起来很牛逼用起来也很牛逼但是不建议使用违背Java代码设计原则
public enum EnumSingleton {INSTANCE;// 注意枚举不是类没有构造方法// 这里可以用来处理业务逻辑public void doSomething() {System.out.println(do something);}public static void main(String[] args) {for (int i 0; i 100; i) {new Thread(() - {System.out.println(EnumSingleton.INSTANCE.hashCode());}).start();}}
}执行一下 还有些其它的方式就不讲了这几种基本就是最常见的大家根据实际业务情况自行选择就好