Servlet单实例以及线程安全小结

Servlet的线程安全问题 文章目录Servlet的线程安全问题引入Servlet的多线程机制如何修复1.实现 SingleThreadModel 接口2.避免使用成员变量3.同步对共享数据的操作思考与小结参考文章 Servlet的线程安全问题 引入 首先看看这样的代码,有什么问题 这里既要求cmd不能包含Calculator又必须要包含Calculator,能做到吗,当然是可以的 Servlet的多线程机制 Servlet实际上是一个单件,当我们第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件或者是 阅读详情

Servlet 3.0笔记之Servlet单实例以及线程安全小结

众所周知,Servlet为单实例多线程,非线程安全的。

若一个Servlet对应多个URL映射,那么将会生成一个还是多个Servlet实例呢?

最好的办法就是动手体验一下

@WebServlet({ "/demoServlet1", "/demoServlet2" })

public class DemoServlet extends HttpServlet {

private static final long serialVersionUID = 1L;



protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

PrintWriter out = response.getWriter();

out.println(request.getServletPath() + "[" + this + "]");

out.flush();

out.close();

}

}

输出结果:

/demoServlet1[com.learn.servlet3.thread.DemoServlet@1320a41]
/demoServlet2[com.learn.servlet3.thread.DemoServlet@9abce9]

输出结果可以看到映射/demoServlet1和/demoServlet2对应Servlet实例是不同的。

结果证明:Servlet将为每一个URL映射生成一个实例;一个Servlet可能存在多个示例,但每一个实例都会对应不同的URL映射。


下面讨论单个Servlet、多线程情况下保证数据线程同步的几个方法。

  1. synchronized:代码块,方法
    大家都会使用的方式,不用详细介绍了。
    建议优先选择修饰方法。
  2. volatile
    轻量级的锁,可以保证多线程情况单线程读取所修饰变量时将会强制从共享内存中读取最新值,但赋值操作并非原子性。
    一个具有简单计数功能Servlet示范:
    /**
    
        * 使用Volatile作为轻量级锁作为计数器
    
        * 
    
        * @author yongboy
    
        * @date 2011-3-12
    
        * @version 1.0
    
        */
    
        @WebServlet("/volatileCountDemo")
    
        public class VolatileCountServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        
    
        private volatile int num = 0;
    
        
    
        protected void doGet(HttpServletRequest request,
    
        HttpServletResponse response) throws ServletException, IOException {
    
        addOne();
    
        response.getWriter().write("now access num : " + getNum());
    
        }
    
        
    
        /**
    
        * 读取开销低
    
        */
    
        private int getNum() {
    
        return num;
    
        }
    
        
    
        /**
    
        * 其写入为非线程安全的,赋值操作开销高
    
        */
    
        private synchronized void addOne() {
    
        num ++;
    
        }
    
        }
    
        
    我们在为volatile修饰属性赋值时,还是加把锁的。
  3. ThreadLocal
    可以保证每一个线程都可以独享一份变量副本,每个线程可以独立改变副本,不会影响到其它线程。
    这里假设多线程环境一个可能落显无聊的示范,初始化一个计数,然后循环输出:
    @WebServlet("/threadLocalServlet")
    
        public class ThreadLocalServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        
    
        private static ThreadLocal threadLocal = new ThreadLocal() {
    
        @Override
    
        protected Integer initialValue() {
    
        return 0;
    
        }
    
        };
    
        
    
        protected void doGet(HttpServletRequest request,
    
        HttpServletResponse response) throws ServletException, IOException {
    
        response.setHeader("Connection", "Keep-Alive");
    
        
    
        PrintWriter out = response.getWriter();
    
        out.println("start... "  + " [" + Thread.currentThread() + "]");
    
        out.flush();
    
        
    
        for (int i = 0; i < 20; i++) {
    
        out.println(threadLocal.get());
    
        out.flush();
    
        
    
        threadLocal.set(threadLocal.get() + 1);
    
        }
    
        
    
        // 手动清理,当然随着当前线程结束,亦会自动清理调
    
        threadLocal.remove();
    
        out.println("finish... ");
    
        out.flush();
    
        out.close();
    
        }
    
        } 
    若创建一个对象较为昂贵,但又是非线程安全的,在某种情况下要求仅仅需要在线程中独立变化,不会影响到其它线程。选择使用ThreadLocal较好一些,嗯,还有,其内部使用到了WeakHashMap,弱引用,当前线程结束,意味着创建的对象副本也会被垃圾回收。
    Hibernate使用ThreadLocal创建Session;Spring亦用于创建对象会使用到一点。
    嗯,请注意这不是解决多线程共享变量的钥匙,甚至你想让某个属性或对象在所有线程中都保持原子性,显然这不是解决方案。
  4. Lock
    没什么好说的,现在JDK版本支持显式的加锁,相比synchronized,添加与释放更加灵活,功能更为全面。
    @WebServlet("/lockServlet")
    
        public class LockServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        
    
        private static int num = 0;
    
        private static final Lock lock = new ReentrantLock();
    
        
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        try{
    
        lock.lock();
    
        num ++;
    
        response.getWriter().println(num);
    
        }finally{
    
        lock.unlock();
    
        }
    
        }
    
        }
    
        
    必须手动释放锁,否则将会一直锁定。
  5. wait/notify
    较老的线程线程同步方案,较之Lock,不建议再次使用。
  6. 原子操作
    原子包装类,包括一些基本类型(int, long, double, boolean等)的包装,对象属性的包装等。
    @WebServlet("/atomicServlet")
    
        public class AtomicServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        private static final AtomicInteger num = new AtomicInteger(0);
    
        
    
        protected void doGet(HttpServletRequest request,
    
        HttpServletResponse response) throws ServletException, IOException {
    
        PrintWriter out = response.getWriter();
    
        out.println(num.incrementAndGet());
    
        out.flush();
    
        out.close();
    
        }
    
        }
    
        
    包装类提供了很多的快捷方法,比如上面的incrementAndGet方法,自身增加1,然后返回结果值,并且还是线程安全的,省缺了我们很多手动、笨拙的编码实现。
    更多原子类,请参见 java.util.concurrent.atomic包。
  7. 一些建议
    尽量不要在Servlet中单独启用线程
    使用尽可能使用局部变量
    尽可能避免使用锁
  8. 数据结构小结
    在平常环境下使用的一些数据结构,在多线程并发环境下可选择使用java.util.concurrent里内置替代品。下面有一个小结,仅供参考。
非线程安全 工具版 JUC版本
HashMap Collections.synchronizedMap ConcurrentHashMap
ArrayList Collections.synchronizedList CopyOnWriteArrayList
HashSet Collections.synchronizedSet synchronizedSet
Queue   ConcurrentLinkedQueue


Servlet线程安全有很太多的话题要说,以上仅仅为蜻蜓点水,真正需要学习和实践的还有一段长路要学习。另,话说,这里已和Servlet版本无关,是知识积累和分享。

Servlet与线程安全 Servlet与线程安全 先说结论,Servlet本身是单例的,线程安全的。但是如果引入共享变量,则可能会变得线程不安全。 1. 什么是线程安全 首先说明一下对线程安全的讨论,哪种情况我们可以称作线程安全? 《Java并发编程实战》给出的定义: 当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的... 阅读详情

相关推荐

Educoder | 计算机网络实验-Ping命令与ICMP协议分析

任务描述本关任务:捕获 Ping 程序生成的数据包。相关知识ping命令Ping 程序是一个简单的工具,允许任何人(例如:网络管理员)验证主机是否存在。源主机中的 Ping 程序将数据包发送到目标 IP 地址;如果目标是在线的,则目标主机中的 Ping 程序将会发送响应 Ping 数据包证明他在线,这两个 Ping 数据包都是 ICMP 数据包。在 Unix/Linux,序列号从 0 开始计数,依次递增。而 Windows 中 ping 程序的 ICMP 序列号是没有规律;;。

Mksg_28的博客 7624

Servlet 3.0笔记之Servlet单实例以及线程安全小结

众所周知,Servlet为单实例多线程,非线程安全的。 若一个Servlet对应多个URL映射,那么将会生成一个还是多个Servlet实例呢? 最好的办法就是动手体验一下@WebServlet({ "/demoServlet1", "/demoServlet2" })public class DemoServlet extends HttpServlet { private static fina...

weixin_30294021的博客 177

SATA硬件电路设计实战:从接口规范到高速布线技巧

本文深入探讨了SATA硬件电路设计的核心要点与实战技巧。从接口物理电气规范、AC耦合电容与阻抗控制等基础,到FPGA/SoC高速收发器选型配置,再到应对6Gbps高速信号的PCB布局布线艺术,系统性地解析了SATA电路设计中的关键挑战与解决方案,助力工程师规避常见陷阱,实现稳定可靠的存储接口设计。

tech5的博客 530

一个Servlet线程安全问题实例

1.问题起源 几年前开发的一个JavaWeb应用,用于课程实验,同一时段内每次使用的用户量大约20人左右,采用的技术框架为Tomcat+Hibernate,功能仅限于简单的增删查改,并没有复杂的逻辑。但是由于当时对JavaWeb只了解皮毛,所以根本没有考虑到线程安全的问题,导致了后来的问题发生。 2.问题症状 1.单机本地功能测试时完全没有问题,多人同时使用时才出现问题; 2.第一年实验过程中未出...

wanxu_pursue的专栏 238

Redis中什么是Big Key(大key)问题?如何解决Big Key问题?

通俗易懂的讲,Big Key就是某个key对应的value很大,占用的redis空间很大,本质上是大value问题。key往往是程序可以自行设置的,value往往不受程序控制,因此可能导致value很大。redis中这些Big Key对应的value值很大,在序列化/反序列化过程中花费的时间很大,因此当我们操作Big Key时,通常比较耗时,这就可能导致redis发生阻塞,从而降低redis性能。用几个实际的例子对大Key的特征进行描述:● 一个String类型的Key,它的值为5MB(数据过大); ● 一

weixiaohuai的博客 3万+

DPO(Direct Preference Optimization)实战全流程指南

《DPO实战全流程指南》摘要 本文提供了端到端的DPO(直接偏好优化)实战方案,包含数据准备、模型训练、评估部署全流程。核心内容包括: 数据构建:推荐UltraFeedback等高质量数据集,提供数据预处理代码 训练配置:基于HuggingFace TRL库的DPO实现,详解beta值等关键参数调优 工业优化:显存节省技巧(LoRA、梯度检查点)、领域自适应方法和在线学习架构 效果评估:量化对比显示DPO可降低86%有害回复率,提升24%用户满意度 常见问题:针对灾难性遗忘、过度安全化等问题给出解决方案 附

技术引领业务创新 1467

深入研究Servlet线程安全性问题

  摘 要:介绍了Servlet多线程机制,通过一个实例并结合Java 的内存模型说明引起Servlet线程不安全的原因,给出了保证Servlet线程安全的三种解决方案,并说明三种方案在实际开发中的取舍。  关键字:Servlet 线程安全 同步 Java内存模型 实例变量   Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是

键者天行 7656

3-RRR并联机器人结构详解:从运动学到奇异点分析(附MATLAB仿真代码)

本文详细解析了3-RRR并联机器人的结构设计、运动学建模及奇异点分析,并提供了MATLAB仿真代码。通过对称性设计和可分析性,3-RRR结构成为教学与研究的理想对象。文章从基础杆件参数设置到奇异位形的实时捕捉,深入探讨了机构运动的数学本质,并分享了仿真调试中的实用技巧,助力工业自动化和精密控制应用。

sunny的博客 364

Servlet 的线程安全问题

Servlet 的线程安全问题 在 Servlet 中使用的是多线程方式来执行 service()方法处理请求,所以我们在使用 Servlet 时需要考虑到线程安全问题,在多线程中对于对象中的成员变量是最不安全的,所以不要在 Servlet 中通过成员变量的方式来存放数据,如果一定要使用成员变量存储数据,在对数据 进行操作时需要使用线程同步的方式来解决线程安全问题,避免出现数据张冠李戴现象。 ...

weixin_42578100的博客 3245

一文搞懂多速率信号处理中信号插值的本质:从插 0、插原值到线性插值!

信号插值在数字信号处理中经常被使用,但“插值”背后究竟发生了什么,却常被忽略。插0、插原值、线性插值看似只是不同的实现方式,实则对应着完全不同的频域效应与滤波特性。本文将结合公式与MATLAB仿真,深入剖析插0、插原值与线性插值三种典型策略的本质区别。

m0_66360845的博客 918

2024年 Flutter 面试题大全(2024.6.28持续更新中)

2024年 Flutter 面试题大全(持续更新中)

Code Metaverse 6664

Servlet线程安全问题及解决

servlet线程安全问题及解决方式

qq_52146944的博客 605

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

servlet单实例多线程模式

前言:Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。 JSP的中存在的多线程问题: 当客户端第一次请求某一个JSP文件时,服务端把该JSP编译成一个CLASS文件,并创建一个该类的实例,然后创建一个线程处理CLIENT端的请求。如果有...

熊浪的博客 1638

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

怎样理解Servlet的单实例多线程

首先明确:Servlet是单实例的,即对于同一种业务请求只有一个是实例。不同的业务请求可以通过分发来产生多个实例。 其次:单实例的原因我想是因为单实例足可以处理某一个请求,就像ibatis的Querydao、UpdateDao一样都是单实例的。 再次:为什么单实例足可以处理某一个请求,因为Servlet是单实例多线程的。 http://hiyachen.cublog.cn  chf@tsin

maxiaokun55的专栏 739

Servlet单实例多线程

01_Servlet的单实例多线程 单线程多实例解释 Servlet在服务器中只会创建一个实例 当多个请求同时请求一个servlet时,就会根据tomcat中的server.xml文件中的标签配置线程池,然后当项目启动时,根据项目中web.xml初始化线程池 当请求到达时,Servlet容器通过程调度线程池中等待状态的线程给请求 线程执行Servlet的service方法 请求结束,放回线程池...

Mamba0824的博客 663

servlet -线程安全

线程安全是 Java 多线程编程中的一个重要概念,特别是在 Web 应用开发中,正确处理线程安全可以避免数据不一致、竞态条件和死锁等问题。Servlet 作为 Java Web 开发的核心组件,由于其单实例多线程的特性,必须特别注意线程安全性。通过合理使用同步方法、同步块、原子类以及无状态设计等方法,可以有效提高 Servlet 的线程安全性和性能。在设计和开发过程中,开发者需要根据具体需求选择合适的同步机制,确保系统在高并发环境下的稳定性和可靠性。

Flying_Fish_roe的博客 1016

Servlet单实例多线程模式

问题:Servlet是线程安全的吗? Servlet类本质上也是一个普通的类,并且Servlet容器默认只允许单个实例存在。当请求到达服务器时,Servlet实例如果已经存在的话则直接加载该实例,如果该Servlet类还未实例化则会先初始化这个Servlet。当请求到达Web服务器时,Web服务器中有一个线程池,它会从线程池中取一个工作线程,通过该线程调用请求的Servlet。因此,对Serv

itmyhome的专栏 1212

servlet单实例多线程

一,servlet容器如何同时处理多个请求。 Servlet采用多线程来处理多个请求同时访问,Servelet容器维护了一个线程池来服务请求。线程池实际上是等待执行代码的一组线程叫做工作者线程(Worker Thread),Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。 当容器收到一个访问Servlet的请求,调度者线程从线程池中选出一个工作者线程,...

sqcwfiu 137

Servlet的单实例多线程

首先明确:Servlet是单实例的,即对于同一种业务请求只有一个是实例。不同的业务请求可以通过分发来产生多个实例。 其次:单实例的原因我想是因为单实例足可以处理某一个请求,就像ibatis的Querydao、UpdateDao一样都是单实例的。 再次:为什么单实例足可以处理某一个请求,因为Servlet是单实例多线程的。 先看一段代码: package hiya.test; publ

robbinBlog 866

【转】怎样理解Servlet的单实例多线程

转自 http://blog.chinaunix.net/uid-7374279-id-3687149.html 首先明确:Servlet是单实例的,即对于同一种业务请求只有一个是实例。不同的业务请求可以通过分发来产生多个实例。其次:单实例的原因我想是因为单实例足可以处理某一个请求,就...

chuanduo6718的博客 133

Servlet 线程安全与并发编程深度解析

每个请求来临时,由容器(如 Tomcat)分配线程处理,这些线程会调用 Controller 方法。从当前线程上下文(ThreadLocal)中注入的,线程之间是互不影响的。Spring 帮你注入的是线程安全的 request,但你写的代码如果有。平时在 Controller 里能随便用这些上下文,其实都是。:Spring Security 用户上下文绑定。实际是由 Spring MVC 使用。(默认是 Spring 单例))的 bean 实例是。Spring 中常用的。:将请求上下文与线程绑定。

NingMaoKing的博客 687

servlet单实例多线程模式!!!!!!!!!

from:http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。   JSP的中存在的多线程问题:  当客户端第一次请求某一个JSP文件时,服务端把该JSP编译成一

dylancao的专栏 816
上一篇: 事务隔离级别
下一篇: javaEE面试重点
network_boy
博客等级 码龄12年 9粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值