这里以经典的数据库驱动连接工具类为例;
数据库连接工具类在各个业务的dao层会被初始化调用;
而每一次初始化都会在堆内存中申请一片空间,这是对堆内存资源的浪费;
如果在堆内存只开辟一片空间,各个业务的Dao层建立不同的引用进行操作,就可以资源利用最大化;
饿汉式(静态常量)
饿汉式(静态代码块)
懒汉式(线程不安全)
懒汉式(线程安全,同步代码块)
懒汉式(线程安全,同步方法)
双重检查
静态内部类
枚举
package com.javaxl.design.single.after;
/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create 2020-02-21 17:09
* 饿汉式(静态常量)
*/
public class DBAccess {
// 构造器私有化,避免外部创建对象
private DBAccess() {
}
// static修饰,保障其能够被静态方法访问
private final static DBAccess dbAccess = new DBAccess();
// 外部直接调用静态方法实例化对象
public static DBAccess getInstance() {
return dbAccess;
}
}
/**
* 饿汉式(静态代码块)
*/
class DBAccess2 {
private DBAccess2() {
}
private static DBAccess2 dbAccess = null;
static {
dbAccess = new DBAccess2();
}
public static DBAccess2 getInstance() {
return dbAccess;
}
}
/**
* 懒汉式(线程不安全)
*/
class DBAccess3 {
private DBAccess3() {
}
private static DBAccess3 dbAccess = null;
public static DBAccess3 getInstance() {
if (dbAccess == null) {
dbAccess = new DBAccess3();
}
return dbAccess;
}
}
/**
* 懒汉式(同步代码块)
*/
class DBAccess4 {
private DBAccess4() {
}
private static DBAccess4 dbAccess = null;
public static DBAccess4 getInstance() {
synchronized (DBAccess4.class) {
if (dbAccess == null) {
dbAccess = new DBAccess4();
}
}
return dbAccess;
}
}
/**
* 懒汉式(线程安全,同步方法)
*/
class DBAccess5 {
private DBAccess5() {
}
private static DBAccess5 dbAccess = null;
public synchronized static DBAccess5 getInstance() {
if (dbAccess == null) {
dbAccess = new DBAccess5();
}
return dbAccess;
}
}
/**
* 双重检查
*/
class DBAccess6 {
private DBAccess6() {
}
private static DBAccess6 dbAccess = null;
public static DBAccess6 getInstance() {
if (dbAccess == null) {
synchronized (DBAccess6.class) {
if (dbAccess == null) {
dbAccess = new DBAccess6();
}
}
}
return dbAccess;
// return new DBAccess6();
}
}
/**
* 静态内部类
*/
class DBAccess7 {
private DBAccess7() {
}
private static class DBAccess7Instance{
private static DBAccess7 dbAccess = new DBAccess7();
}
public static DBAccess7 getInstance() {
return DBAccess7Instance.dbAccess;
}
}
/**
* 枚举
*/
enum DBAccess8{
DBACCESS;
public static DBAccess8 getInstance() {
return DBAccess8.DBACCESS;
}
}
结论:
单例中两种饿汉式可用,但是存在性能问题
单例中三种懒汉式不推荐,存在线程安全问题,同步方法的方式解决了线程的问题,但是性能极差
最后三种单例模式值得推荐
注意事项
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
应用
jdk源码中Runtime类
tomcat中ApplicationContext类
session 工厂
建议单例使用饿汉式,代码更加简洁,
单例模式的使用场景
这里举个简单的例子,网站访问量统计
在不考虑设计模式这一因素的情况下,我们最初是怎么统计网站统计量的呢?
这里需要写一个监听类、两个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的效果
备案号:湘ICP备19000029号
Copyright © 2018-2019 javaxl晓码阁 版权所有