java单例模式实现的方法是什么

这篇文章主要讲解了“java单例模式实现的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java单例模式实现的方法是什么”吧!

柳城网站建设公司创新互联,柳城网站设计制作,有大型网站制作公司丰富经验。已为柳城1000多家提供企业网站建设服务。企业网站搭建\外贸网站制作要多少钱,请找那个售后服务好的柳城做网站的公司定做!

许多人都了解,单例的创建大致可以分为两种:

  • 饱汉型

  • 饿汉型

所谓饿汉型,就是单例的对象,我上来就先创建好了,什么时候用直接拿就好了。例如这样的方式:

private static final Singleton singleton = new Singleton();
 
public static Singleton getInstance() {
   return singleton;
}

这样的实现方式没有任何问题。问题出在哪呢?

有些时候,要实现Singleton的对象比较大,或者创建比较耗资源,耗时等,我们希望能在需要的时候再初始化,而不放在class 加载的时候,也就是实现所谓的lazy load。

这个时候问题就来了,这种所谓的饱汉型要怎么写呢?

你可能见到过这种形式的实现

private static Singleton singleton;
public static Singleton getInstance() {
   if (singleton == null) {
       singleton = new Singleton();
   }
   return singleton;
}

这样的实现,有问题么?是不是感觉棒棒的?

在单线程的环境中跑的话,这样也是可以保证只返回一个instance的。

问题出在多线程环境下执行。

多个线程执行时,极有可能两个线程同时执行到判断是否为null的情况,又同时创建了实例出来。为了解决多线程的问题,你毫不犹豫的给方法加上了synchronized,兵不血刃的解决了问题。

问题又来了!

当这个方法使用很频繁的时候,synchronized带来的互斥效果,导致每次只能一个线程执行,效率很低。

此时,一个聪明的想法浮现在脑海(当然,可能是查资料,网上浏览了解到的)。使用双重锁检查(Double lock checking)来提高效率,实现起来是这个样子:

public static Single getInstance() {
   if(singleton == null) {
       synchronized(this) {
           if(singleton == null) {
               singleton = new Singletoon();
           }
       }
   }
   return singleton;
}

我们的方法并不是互斥的,只有在instance为空时才会加锁检查。看似无懈可击!

这个时候有一个问题,是看似普通的new XXX这种操作,其本质上和i++

这种操作一样,并不是一个原子操作。例如,我们下面这几行代码:

public class Test {
   private int i = 5;
   private int a = 2;
   public Test(int i, int a) {
       this.i = i;
       this.a = a;
   }
   public void ttt() {
      Test t = new Test(1,1); //普通的实例化一个对象
   }
}

大致包含的步骤有:

  1. 创建对象

  2. 初始化对象的各个域,为其赋值

  3. 将对象指向其引用

但是,对于这些指令的执行,却并不一定是按照这个顺序执行,为了执行效率,这些指令会被优化,指令被重新排序。极有可能对象被创建后即指向了其引用,但各个域并没有初始化,如果此时被使用,那拿到的就是一个构造不完整的对象。(可以参考Java并发编程实战了解对象逃逸)

为了使代码不被优化影响,Java 5在修订了Java内存模型(JMM)之后,可以使用volatile声明,不允许指令重排序

volatile关键字同时保证了内存的有序性可见性,保证程序可以按照预期执行。所以,要实现一个正确无误的DCL单例,需要同时把singleton对象声明为

volatile,这一定很重要

如果不使用DCL,我们还有其它方式实现延迟初始化。例如下面这种内部类的形式,也是比较常用的。

public class Foo {
   private static class FooHolder {
       static final Foo foo = new Foo();
   }
   public static Foo getFoo() {
       return FooHolder.foo;
   }
}

由于内部类只有在使用时才会初始化,所以保证了单例的延迟初始化。

了解了以上这些后,我们来看Tomcat中的单例,是如何使用的。

首先我们来看看Tomcat中对于DCL的使用。

/** Whether the servlet needs reloading on next access */
private volatile boolean reload = true;
 

public Servlet getServlet() throws ServletException {
   // DCL on 'reload' requires that 'reload' be volatile
   // (this also forces a read memory barrier, ensuring the
   // new servlet object is read consistently)
   if (reload) {
       synchronized (this) {
           // Synchronizing on jsw enables simultaneous loading
           // of different pages, but not the same page.
           if (reload) {
               // This is to maintain the original protocol.
               destroy();
               final Servlet servlet;
               servlet.init(config);
               reload = false;
               // Volatile 'reload' forces in order write of 'theServlet' and new servlet object
           } }  }
   return theServlet;
}

上面的代码是关于jsp对应的Servlet获取时对应的代码,其中对于DCL的使用主要用于判断jsp文件对应的class是否需要重新加载。(jsp文件工作原理前面文章介绍过,感兴趣的朋友可以看JSP文件修改实时生效的秘密)

单例的使用,Tomcat中的方式很简单,

public final class ApplicationFilterFactory {

   private static ApplicationFilterFactory factory = null;

   private ApplicationFilterFactory() {
       // Prevent instantiation outside of the getInstanceMethod().
   }
 
/**
* Return the factory instance.
*/
public static ApplicationFilterFactory getInstance() {
   if (factory == null) {
       factory = new ApplicationFilterFactory();
   }
   return factory;
}

我们看到和前面第一次提到的饱汉型一样,没有使用DCL,也没加

synchronized,这是因为在Tomcat中对于此处ApplicationFactory的使用,只有在StandardWrapperValve启动才会触发其初始化,并不会涉及到多线程环境的使用,所以可以放心使用这种方式。

看到这里的朋友,其实单例还有一种实现方式,是Effective Java的作者推荐使用的,使用起来更简单,只需要一个枚举项的enum即可,之后可以包含其对应的各个方法:

public enum Singleton {
   INSTANCE;
   public void test() {
       System.out.println("test");
   }
}

而我们使用的时候,直接这样使用即可:

Singleton.INSTANCE.test();

感谢各位的阅读,以上就是“java单例模式实现的方法是什么”的内容了,经过本文的学习后,相信大家对java单例模式实现的方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!

网站标题:java单例模式实现的方法是什么
转载源于:https://www.cdcxhl.com/article2/pdgdoc.html

成都网站建设公司_创新互联,为您提供企业网站制作手机网站建设定制开发商城网站网站维护关键词优化

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

手机网站建设