当前位置: 首页 > news >正文

网站建设贵州上海网店代运营外包

网站建设贵州,上海网店代运营外包,电话销售做网站认证,html网站建设中源代码在项目中为了避免创建大量的对象#xff0c;频繁出现gc的问题#xff0c;单例设计模式闪亮登场。 一、饿汉式 1.1饿汉式 顾名思义就是我们比较饿#xff0c;每次想吃的时候#xff0c;都提前为我们创建好。其实我记了好久也没分清楚饿汉式和懒汉式的区别。这里给出我的一…在项目中为了避免创建大量的对象频繁出现gc的问题单例设计模式闪亮登场。 一、饿汉式 1.1饿汉式 顾名思义就是我们比较饿每次想吃的时候都提前为我们创建好。其实我记了好久也没分清楚饿汉式和懒汉式的区别。这里给出我的一个记忆方法懒汉式就是懒加载什么是懒加载呢就是我们需要的时候给创建对象就行稍后介绍懒汉式的时候你会发现这个现象。 1.2饿汉式的特点 线程安全但是如果一个项目需要创建大量的对象的时候当项目运行的时候会创建大量我们暂时用不到的对象。 1.3饿汉式代码 package singletonModel; public class HungrySingleton {public static HungrySingleton instancenew HungrySingleton();private HungrySingleton(){}public static HungrySingleton getInstance(){return instance;} }1.4多线程下测试 package Test; import singletonModel.DoubleLockSingleton;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; public class SingletonTest {public static void main(String[] args) {// 使用AtomicReference来存储第一次获取到的LazySingleton实例AtomicReferenceDoubleLockSingleton singletonInstance new AtomicReference();// 我们将启动大量线程来尝试突破单例的线程安全性ExecutorService executorService Executors.newFixedThreadPool(100);// 用于发现多个实例创建的标志AtomicReferenceBoolean flag new AtomicReference(false);// 提交多个任务到线程池尝试并发地获取单例实例for (int i 0; i 100; i) {executorService.submit(() - {DoubleLockSingleton instance DoubleLockSingleton.getInstance();// 如果原子引用为空我们设置当前实例if (singletonInstance.get() null) {singletonInstance.set(instance);} else if (singletonInstance.get() ! instance) {// 如果原子引用中的实例与当前获取的实例不同说明存在多个实例flag.set(true);System.out.println(Detected multiple instances!);}});}executorService.shutdown();// 等待所有任务完成while (!executorService.isTerminated()) {// 等待所有线程执行完毕}if (flag.get().equals(false)) {System.out.println(No multiple instances detected!);}} } 1.5运行结果 通过实验证明饿汉式在多线程环境下是线程安全的 二、懒汉式 2.1懒汉式 顾名思义比较懒叫我们的时候我们在穿衣服去干活即完成对象的创建的过程。 2.2懒汉式的特点 需要的时候才为我们创建能够避免在项目启动的时候创建大量的无用对象减少GC。缺点就是多线程操作下线程不安全 2.3懒汉式代码 package singletonModel; public class LazySingleton {private static LazySingleton lazyInstance;private LazySingleton(){}public static LazySingleton getInstance(){if(lazyInstancenull){lazyInstance new LazySingleton();}return lazyInstance;} } 2.4多线程下测试 package Test; import singletonModel.LazySingleton; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; public class SingletonTest {public static void main(String[] args) {// 使用AtomicReference来存储第一次获取到的LazySingleton实例AtomicReferenceLazySingleton singletonInstance new AtomicReference();// 我们将启动大量线程来尝试突破单例的线程安全性ExecutorService executorService Executors.newFixedThreadPool(100);// 用于发现多个实例创建的标志AtomicReferenceBoolean flag new AtomicReference(false);// 提交多个任务到线程池尝试并发地获取单例实例for (int i 0; i 100; i) {executorService.submit(() - {LazySingleton instance LazySingleton.getInstance();// 如果原子引用为空我们设置当前实例if (singletonInstance.get() null) {singletonInstance.set(instance);} else if (singletonInstance.get() ! instance) {// 如果原子引用中的实例与当前获取的实例不同说明存在多个实例flag.set(true);System.out.println(Detected multiple instances!);}});}executorService.shutdown();// 等待所有任务完成while (!executorService.isTerminated()) {// 等待所有线程执行完毕}if (flag.get().equals(false)) {System.out.println(No multiple instances detected!);}} }上述代码需要多次测试就能够测试出线程不安全的 2.5测试结果 测试证明懒汉式在多线程操作下是线程不安全的 2.6具体原因 具体的原因就是发生在下图的位置即多线程环境下不知线程哪个执行快慢即存在两个线程AB线程A在进入if语句的时候判断为空然后完成对象的创建但是对象的创建也需要一定时间这个时候线程B也进入if判断当前线程A还没有创建好则判断为null同时也完成对象的创建这时候线程AB创建的对象就不是同一个对象了。也就是线程不安全的了即不满足原子性可见性有序性。 三、懒汉式方案修补方案一 为了保证线程安全即满足原子性可见性有序性。我们首先想到的就是加锁 由于getInstance方法为static修饰的方式我们加了synchronized后锁住的是当前的类即加的类锁。即多线程操作该类的时候只有1个线程操作成功 3.1代码 package singletonModel;public class RLazySingleton {static RLazySingleton instance;private RLazySingleton(){}synchronized public static RLazySingleton getInstance(){if(instancenull){instancenew RLazySingleton();}return instance;} } 3.2多线程测试代码 package Test; import singletonModel.RLazySingleton;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference;public class SingletonTest {public static void main(String[] args) {// 使用AtomicReference来存储第一次获取到的LazySingleton实例AtomicReferenceRLazySingleton singletonInstance new AtomicReference();// 我们将启动大量线程来尝试突破单例的线程安全性ExecutorService executorService Executors.newFixedThreadPool(100);// 用于发现多个实例创建的标志AtomicReferenceBoolean flag new AtomicReference(false);// 提交多个任务到线程池尝试并发地获取单例实例for (int i 0; i 100; i) {executorService.submit(() - {RLazySingleton instance RLazySingleton.getInstance();// 如果原子引用为空我们设置当前实例if (singletonInstance.get() null) {singletonInstance.set(instance);} else if (singletonInstance.get() ! instance) {// 如果原子引用中的实例与当前获取的实例不同说明存在多个实例flag.set(true);System.out.println(Detected multiple instances!);}});}executorService.shutdown();// 等待所有任务完成while (!executorService.isTerminated()) {// 等待所有线程执行完毕}if (flag.get().equals(false)) {System.out.println(No multiple instances detected!);}} } 3.3测试结果 实验结果证明这种测试代码也是线程安全的 3.4存在的问题 通过在getInstance()方法上添加synchronized关键字可以强制每次只有一个线程能够访问方法从而避免竞态条件。但这样做会影响性能因为每次访问都需要进行同步。 四、双重锁检测方案 解决每次访问都需要进行同步的问题。 4.1代码 package singletonModel; public class DoubleLockSingleton {private static DoubleLockSingleton instance;private DoubleLockSingleton(){}public static DoubleLockSingleton getInstance(){if(instancenull){synchronized (DoubleLockSingleton.class){if(instancenull){instancenew DoubleLockSingleton();}}}return instance;} } 4.2测试代码 package Test; import singletonModel.DoubleLockSingleton; import singletonModel.RLazySingleton; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; public class SingletonTest {public static void main(String[] args) {// 使用AtomicReference来存储第一次获取到的LazySingleton实例AtomicReferenceRLazySingleton singletonInstance new AtomicReference();// 我们将启动大量线程来尝试突破单例的线程安全性ExecutorService executorService Executors.newFixedThreadPool(100);// 用于发现多个实例创建的标志AtomicReferenceBoolean flag new AtomicReference(false);// 提交多个任务到线程池尝试并发地获取单例实例for (int i 0; i 100; i) {executorService.submit(() - {RLazySingleton instance RLazySingleton.getInstance();// 如果原子引用为空我们设置当前实例if (singletonInstance.get() null) {singletonInstance.set(instance);} else if (singletonInstance.get() ! instance) {// 如果原子引用中的实例与当前获取的实例不同说明存在多个实例flag.set(true);System.out.println(Detected multiple instances!);}});}executorService.shutdown();// 等待所有任务完成while (!executorService.isTerminated()) {// 等待所有线程执行完毕}if (flag.get().equals(false)) {System.out.println(No multiple instances detected!);}} } 测试结果 实验结果也是线程安全的。 五、其他线程安全的写法 5.1静态内部类 public class StaticInnerClassSingleton {private static class LazyHolder {private static final StaticInnerClass INSTANCE new StaticInnerClass();}private StaticInnerClass(){}public static StaticInnerClass getInstance(){return LazyHolder.INSTANCE;} } 5.2枚举类 package singletonModel;public enum EnumSingleton {Instance;public void getInstance(){System.out.println(枚举类创建对象);} } 六、总结 在Java中使用枚举enum实现的单例模式是唯一能够抵御反射攻击的方式因为枚举类型没有构造方法在字节码层面是有私有构造器的但这是由编译器自己添加的所以无法通过反射来实例化枚举类型。 枚举攻击 import java.lang.reflect.Constructor;public class ReflectionSingletonAttack {public static void main(String[] args) {Singleton instanceOne Singleton.getInstance();Singleton instanceTwo null;try {// 获取Singleton类的构造函数Constructor[] constructors Singleton.class.getDeclaredConstructors();for (Constructor constructor : constructors) {// 设置构造函数的访问权限为可访问constructor.setAccessible(true);// 使用构造函数创建一个新的Singleton实例instanceTwo (Singleton) constructor.newInstance();break;}} catch (Exception e) {e.printStackTrace();}// 打印两个实例的哈希码System.out.println(Instance 1 hash: instanceOne.hashCode());System.out.println(Instance 2 hash: instanceTwo.hashCode());} } 枚举类单例模式抵挡枚举攻击 import java.lang.reflect.Constructor;public class EnumReflectionAttack {public static void main(String[] args) {EnumSingleton instanceOne EnumSingleton.INSTANCE;EnumSingleton instanceTwo null;try {Constructor[] constructors EnumSingleton.class.getDeclaredConstructors();for (Constructor constructor : constructors) {constructor.setAccessible(true);instanceTwo (EnumSingleton) constructor.newInstance();break;}} catch (Exception e) {e.printStackTrace();}System.out.println(Instance 1 hash: instanceOne.hashCode());System.out.println(Instance 2 hash: (instanceTwo ! null ? instanceTwo.hashCode() : instance creation failed));} } 在运行此代码时您会收到类似以下的异常 java.lang.IllegalArgumentException: Cannot reflectively create enum objects因此使用枚举的方式创建单例是安全的它有效地防止了反射攻击以及解决了序列化问题。这也是为什么很多推荐使用枚举方式来实现单例模式的原因之一。
http://www.w-s-a.com/news/331131/

相关文章:

  • 公司做哪个网站比较好巴顿品牌设计官网
  • 济宁北湖建设局网站我要推广
  • mc网站的建设大型网站开发
  • 给网站做推广一般花多少钱全国最大的外发加工网
  • linux 网站301江西seo推广方案
  • c2c电子商务网站定制开发wordpress html单页
  • 查询网站空间商自己做的网站如何放到微信
  • 现在网站开发哪个语言好月嫂公司网站建设构思
  • 腾讯云免费网站建设网站设计一级网页
  • 网站备案系统验证码出错的解决方案wordpress+论坛+注册
  • 代做毕设的网站先做网站先备案
  • 网站定制哪个好wordpress主题dux1.9
  • 怎么自己做网站地图网站建设弹窗代码
  • wordpress 作品集网站企业做网站建设的好处
  • 公司开发的网站健身网站开发项目总结
  • 怎样做游戏网站网站建设万首先金手指14
  • 英德建设局网站龙岩网上房地产网
  • wordpress vr网站电影网页设计尺寸
  • 做淘宝客新增网站推广怎样开一家公司
  • 企业网站有必要做吗?网站平均停留时间
  • 蘑菇街的网站建设凡科网站建设网页怎么建
  • 中国光大国际建设工程公司网站论坛是做网站还是app好
  • 地产集团网站建设高德是外国公司吗?
  • 天津市网站建站制作网站建设新报价图片欣赏
  • 怎么样在百度搜到自己的网站高端房产网站建设
  • 邯郸做移动网站多少钱ui设计好就业吗
  • 共享虚拟主机普惠版做网站产品推广包括哪些内容
  • 广州市网站建站免费咨询医生有问必答
  • app网站建设制作哪个网站可以做魔方图片
  • 教育培训网站建设方案模板下载网站文风