资讯动态

Java面试基础

发布时间:2026/9/29 11:16:09 来源:尧图企业网站定制
Servlet的多线程同步问题servlet 是单实例多线程的工作模式服务器只会为每个 Servlet 创建一个实例对象所有客户端请求都会复用这个实例由多个线程并发调用service()/doGet()/doPost()方法处理请求。这就带来了多线程同步问题如果 Servlet 中定义了实例变量多个线程同时读写会引发数据错乱、线程安全问题。一、核心原理为什么会有线程安全问题Servlet 生命周期服务器启动 / 第一次访问时创建1 个 Servlet 实例后续所有请求都由新线程调用这个实例的方法服务器关闭销毁实例线程安全的根源局部变量线程安全每个线程独立栈内存互不干扰实例变量 / 静态变量非线程安全所有线程共享堆内存中的同一个对象二、解决方案推荐优先级从高到低方案 1【最佳】使用局部变量首选把共享的实例变量改成方法内的局部变量从根源避免共享。public class SafeServlet extends HttpServlet { // 不定义实例变量 Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { // 局部变量线程安全每个线程独立拥有 String userName request.getParameter(name); try { Thread.sleep(1000); response.getWriter().write(用户 userName); } catch (Exception e) { e.printStackTrace(); } } }优点无锁、高性能、代码简洁是 Servlet 开发标准规范。方案 2使用 ThreadLocal 存储线程私有数据如果必须用实例变量用ThreadLocal实现线程隔离每个线程只操作自己的数据。public class ThreadLocalServlet extends HttpServlet { // 线程本地变量每个线程独立副本 private ThreadLocalString userLocal new ThreadLocal(); Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { // 存入当前线程的数据 userLocal.set(request.getParameter(name)); Thread.sleep(1000); // 获取当前线程的数据互不干扰 response.getWriter().write(用户 userLocal.get()); } finally { // 必须手动清除防止内存泄漏 userLocal.remove(); } } }方案 3同步代码块慎用会降低性能使用synchronized加锁让代码串行执行但会阻塞并发请求高并发下性能极差。public class SyncServlet extends HttpServlet { private String userName; Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { // 加锁同一时间只有一个线程执行 synchronized (this) { userName request.getParameter(name); try { Thread.sleep(1000); response.getWriter().write(用户 userName); } catch (Exception e) { e.printStackTrace(); } } } }三、哪些对象是线程安全 / 不安全的对象作用域线程安全说明HttpServletRequest请求✅ 安全每个请求独立对象HttpServletResponse请求✅ 安全每个请求独立对象局部变量方法✅ 安全线程私有Servlet 实例变量应用❌ 不安全多线程共享静态变量应用❌ 不安全全局共享ServletContext应用❌ 不安全全局共享需要加锁HttpSession会话❌ 不安全同一用户多请求共享request.getParameter()和getAttribute()的区别一、核心本质区别getParameter()获取浏览器提交的请求参数是客户端 → 服务器传来的数据只读、字符串类型、天生跨请求传输。getAttribute()获取服务端域对象中手动存入的属性数据是服务器内部自己存、自己取的数据可增删改、任意类型仅在当前域范围内有效。二、全方位对比1. 数据来源getParameter()来自表单、URL 拼接参数、ajax 请求参数、地址栏keyvaluegetAttribute()来自服务端代码手动调用request.setAttribute(key,value)存入2. 数据类型getParameter()永远返回 String多参数数组用getParameterValues()getAttribute()返回 Object需要手动强转String、集合、实体类对象等3. 可读写性getParameter()只能获取不能修改 / 设置无setParameter()方法getAttribute()可读可写搭配setAttribute()/removeAttribute()使用4. 生命周期 作用范围getParameter()只针对单次请求请求结束参数自动销毁天然跟随一次请求。getAttribute()数据绑定在request域对象中一次请求、多次转发间共享重定向会产生新 request属性直接丢失。5. 使用场景getParameter()接收用户输入账号、密码、查询条件、表单提交数据。getAttribute()服务端数据流转Servlet 查询数据 → 存入 request → 转发到 JSP / 其他 Servlet 展示。三、转发 重定向 关键区别必考请求转发forward一次请求request对象不变 参数保留、getAttribute()数据保留重定向redirect两次请求新建request 原有 parameter 无保留、getAttribute()数据全部丢失

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑