当前位置: 首页 > Web前端 > HTML5

Java单例模式总有你想不到的知识

时间:2023-04-05 23:00:04 HTML5

文章目录Java单例模式单例模式是Java中最简单的设计模式之一。这类设计模式属于创建模式,它提供了创建对象的最佳方式。单例模式保证了某个类在一个应用中只有一个实例,并实例化自己并将这个实例单例提供给整个系统。示例实例。单例模式应该只在有真正的“单实例”需求时使用:单例类只能有一个实例单例类必须自己创建自己唯一的实例单例类必须为所有其他对象提供一个实例,两种形式Java中单例模式的实现可以有两种形式:懒人模式(类加载时不初始化)饿人模式(类加载时就完成了初始化,所以类加载慢,但是对象可以获取)速度快)设计要求写单例时必须满足以下条件:构造方法变为private,提供静态方法获取单例对象。线程在初始化之前可以访问域),但是实例是在类加载的时候实例化的,此时初始化实例显然没有达到延迟加载(lazyloading)的效果。两种形式:packagecom.shixun.design.singleton;publicclassSingleton1{privatestaticSingleton1instance=newSingleton1();//私有构造方法,保证外界无法直接实例化。privateSingleton1(){}//通过publicstatic方法获取对象实例publicstaticSingleton1getInstance(){returninstance;}}也可以将静态对象初始化放在静态代码块包中com.shixun.design.singleton;publicclassSingleton2{privatestaticSingleton2instance=null;//对象初始化放在静态代码块中static{instance=newSingleton2();}//私有构造方法,保证外界无法直接实例化。privateSingleton2(){}//通过publicstatic方法获取对象实例publicstaticSingleton2getInstance(){returninstance;}}以惰性方式实现单例模式可以提高类加载性能。加载内部同步机制的线程安全是不同的。懒加载时需要注意单例实例的线程安全。如果简单粗暴地实现,会导致在多线程环境下运行异常。例如下面的代码会引发异常:packagecom.shixun.design.singleton;公共类Singleton3{私有静态Singleton3实例;privateSingleton3(){}publicstaticSingleton3getInstance(){if(instance==null){instance=newSingleton3();}返回实例;}}当以上代码被多个线程同时访问时,可能会产生多个实例,甚至会销毁实例。违反了单例设计原则,可以用如下代码测试:packagecom.shixun.design。单例;公共类SingletonTest实现Runnable{@Overridepublicvoidrun(){Singleton3singleton3=Singleton3.getInstance();System.out.println(singleton3);}publicstaticvoidmain(String[]args){for(inti=0;i<10;i++){SingletonTestmyThread=newSingletonTest();线程thread=newThread(myThread,String.valueOf(i));线程thread2=newThread(myThread,String.valueOf(i));线程thread3=newThread(myThread,String.valueOf(i));线。开始();thread2.start();thread3.start();}}}惰性多线程解决方案synchronized可以为返回单例实例的方法设置同步,保证线程安全包com.shixun.design.singleton;公共类Singleton4{私有静态Singleton4实例;privateSingleton4(){}publicsynchronizedstaticSingleton4getInstance(){if(instance==null){instance=newSingleton4();}返回实例;在线程中效果很好,好像也有不错的延迟加载(lazyloading),但遗憾的是,因为整个方法都是synchronized,所以效率比较低。双重检查锁方法使用双重检查锁。第二种情况==null判断第一种判断是没有锁。如果install不为null,则直接返回单实例对象,提高效率。第二个判断是防止多线程创建多个实例。如果两个线程A和B同时竞争synchronizedLock,A先抢到锁,B等待,A线程实例赋值实例化对象,释放锁,B线程获取锁,如果没有二次判断,则会直接创建object,那么不符合单例的要求,需要给这个静态对象加上volatile关键字。volatile在这里的作用是通知其他线程及时更新变量;保证顺序,禁止指令重排序,及时通知其他线程更新变量,简单明了。第二个函数是这样的,我们举个例子来说明一下:例子的原因:在执行instance=newSingleton()语句的时候,一共有三个操作。在堆中分配内存并调用构造函数进行初始化并将实例引用指向内存地址。在这三个步骤中,指令可能会被重新排序,即有两种可能的结果:123和132(无论如何重新排序,单线程程序的执行结果都不会改变)如果A线程执行到instance=newSingleton(),此时2和3重新排序。如果选择执行3,实例不再为null,但指向的对象还没有初始化。如果此时B对象判断实例不为null,则直接返回一个未初始化的对象。double-checklock方法的代码如下:packagecom.shixun.design.singleton;公共类Singleton5{privatevolatilestaticSingleton5实例;privateSingleton5(){}//使用双重检查锁方法publicstaticSingleton5getInstance(){if(instance==null){synchronized(Singleton5.class){if(instance==null){instance=newSingleton5();}}}返回实例;}}再次测试,没问题:packagecom.shixun.design.singleton;公共类SingletonTest实现Runnable{@Overridepublicvoidrun(){Singleton5singleton5=Singleton5.getInstance();System.out.println(singleton5);}publicstaticvoidmain(String[]args){for(inti=0;i<10;i++){SingletonTestmyThread=newSingletonTest();线程thread=newThread(myThread,String.valueOf(i));线程thread2=newThread(myThread,String.valueOf(i));线程thread3=newThread(myThread,String.valueOf(i));线程thread4=newThread(myThread,String.valueOf(i));线程thread5=newThread(myThread,String.valueOf(i));线。开始();thread2.start();thread3.start();thread4.start();thread5.开始();之前提到过静态内部类,在任何线程访问实例之前都会进行静态初始化对其进行初始化,因此,可以利用这个特性改造惰性单例:静态内部类加载机制:仅当它被使用,在多线程的情况下,类加载器可以保证只加载一个字节码代码如下:=新单例6();}privateSingleton6(){}publicstaticfinalSingleton6getInstance(){returnSingletonHolder.Instance;voidsay(){System.out.println("调用了say方法");}publicstaticvoidsayHello(){System.out.println("调用了sayHello方法");}测试也OK:packagecom.shixun.design.singleton;publicclassSingletonTestimplementsRunnable{@Overridepublicvoidrun(){Singleton6singleton6=Singleton6.getInstance();System.out.println(singleton6);singleton6.say();}publicstaticvoidmain(String[]args){for(inti=0;i<10;i++){SingletonTestmyThread=newSingletonTest();Threadthread=newThread(myThread,String.valueOf(i));Threadthread2=newThread(myThread,String.valueOf(i));Threadthread3=newThread(myThread,String.valueOf(i));Threadthread4=newThread(myThread,String.valueOf)(i));Threadthread5=newThread(myThread,String.valueOf(i));thread.start();thread2.start();thread3.start();thread4.start();thread5.start();}}}枚举(不要盲目使用)枚举是在JDK1.5之后引入的,由于枚举的特性,可以用来实现单例,它不仅可以避免多线程同步问题,并且还可以防止反序列化重新创建新的对象(序列化和反序列化后的同一个对象)。代码如下packagecom.shixun.design.singleton;公共枚举Singleton7{实例;公共无效说(){系统。out.println("向你问好!");}}测试一下:packagecom.shixun.design.singleton;公共类SingletonTest实现Runnable{@Overridepublicvoidrun(){Singleton7singleton7=Singleton7.INSTANCE;System.out.println(singleton7.hashCode());singleton7.say();}publicstaticvoidmain(String[]args){for(inti=0;i<10;i++){SingletonTestmyThread=newSingletonTest();线程thread=newThread(myThread,String.valueOf(i));线程thread2=newThread(myThread,String.valueOf(i));线程thread3=newThread(myThread,String.valueOf(i));线程thread4=newThread(myThread,String.valueOf(i));线程thread5=newThread(myThread,String.valueOf(i));线。开始();thread2.start();thread3.start();thread4.start();thread5.开始();}}/***生写懒汉式多线程问题*/privatestaticvoidmethod01(){for(inti=0;i<100;i++){SingletonTestmyThread=newSingletonTest();线程thread=newThread(myThread,String.valueOf(i));线程thread2=newThread(myThread,String.valueOf(i));线程thread3=newThread(myThread,String.valueOf(i));thread.start();thread2.start();thread3.start();}}}