单例模式Singleton(创建模式)

一曲冷凌霜 提交于 2019-12-11 10:06:15

定义:

Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。

在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作。

还有, singleton能够被状态化; 这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到。

另外方面,Singleton也能够被无状态化。提供工具性质的功能,

Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。

我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。

单例模式的两种代码体现形式

饱汉式

 //    定义一个私有构造器,这样的话就不能通过new关键字在外部所实例化
    private Singleton(){}

//    在jvm中创建该类的一个实例
    private static Singleton singleton = new Singleton();

//    在外部通过调用此方法,访问该类的仅有的一个实例,达到该类资源共享的一个效果
    public static Singleton getInstance(){
        return singleton;
    }

懒汉式

//    定义一个私有构造器,这样的话就不能通过new关键字在外部所实例化
    private Singleton2(){}

//    在jvm中创建该类的一个实例
    private static Singleton2 singleton = null;

//    在外部通过调用此方法,访问该类的仅有的一个实例,达到该类资源共享的一个效果
    public static synchronized Singleton2 getInstance(){
        if(null == singleton)
            singleton = new Singleton2();
        return singleton;
    }

后期追加内容:

对一类问题行之有效的解决方案
单例设计模式
特点:解决一个类在内存中只存在一个对象。

案例:两个人操作同一个文件,将文件描述成类的话,那么两个人操作这个对象。用new的方法来操作的话,那么实际上是两个人操作的是不同的对象。这个时候,我们就需要让该类只能产生一个对象,供两个人来操作了,就需要用单例了。Tomcat的容器就是单例的。

饿汉式代码及内存原理图

在这里插入图片描述

懒汉式源码

在这里插入图片描述

建议单例使用饿汉式,代码更加简洁

单例模式的使用场景

这里举个简单的例子,网站访问量统计

在不考虑设计模式这一因素的情况下,我们最初是怎么统计网站统计量的呢?

这里需要写一个监听类、两个servlet来、一个JSP页面模拟网站访问统计的场景

public class InitListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext context = sce.getServletContext();
        context.setAttribute("count",0);
    }
}

DemoServlet1.java

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = req.getServletContext();
        int count = (int) context.getAttribute("count");
        context.setAttribute("count",++count);
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }

DemoServlet2.java

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = req.getServletContext();
        int count = (int) context.getAttribute("count");
        context.setAttribute("count",++count);
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }

index.jsp

全局作用域统计网站访问量:${count}

那么不使用全局作用域,我们能否统计网站的访问量呢?

答案是肯定的,servlet中全局作用域之所以能够统计网站的访问量,缘由在于servlet容器是单例的,工程一旦启动完毕,application作用域是只有一个的,

关于网站中的所有请求用到的application都是同一个,所以我们可以那它用来统计访问量。参照这一原理,我们可以用单例模式来统计网站访问量。代码

如下:

这里可以不需要监听类

两个servlet代码如下,代码完全一致

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = req.getServletContext();
        int count = (int) context.getAttribute("count");

        Singleton singleton = Singleton.getInstance();
        singleton.setCount(singleton.getCount()+1);

        context.setAttribute("count",++count);
        req.setAttribute("count2",singleton.getCount());
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }

index.jsp

全局作用域统计网站访问量:${count}
单例模式统计网站访问量:${count2}

不管是移动端、还是电脑端,只要同一局域网,那么访问

http://localhost:8080/design/demo1

http://localhost:8080/design/demo2

都可以达到访问量+1的效果

在这里插入图片描述
谢谢大家,多多指教!!!
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!