servlet多线程安全问题(转)

使用CLion在Window端进行linux开发         以往不管是开发x86端linux程序还是arm端linux程序,都是使用Source Insight作为源码编辑工具的,如下图      去年底,发现CLion的2018.3更新版本,可以支持remote host开发了,大爱!     我是基于以下几点原因,将开发工具换成CLion 1. 语法高亮较明显、跳转、重构方便(我很看重这个); 2. 可以使用图形界面进行调... 阅读详情

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。 这样,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误。

实例变量不正确的使用是造成Servlet线程不安全的主要原因。下面针对该问题给出了三种解决方案并对方案的选取给出了一些参考性的建议。

  1、实现 SingleThreadModel 接口

  该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。这种方法只要将前面的Concurrent Test类的类头定义更改为:

Public class Concurrent Test extends HttpServlet implements SingleThreadModel {
     …………
} 

  2、同步对共享数据的操作

  使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,在本论文中的Servlet可以通过同步块操作来保证线程的安全。同步后的代码如下: 

…………
Public class Concurrent Test extends HttpServlet { …………
Username = request.getParameter ("username"); 
Synchronized (this){
Output = response.getWriter (); 
Try {
Thread. Sleep (5000);
} Catch (Interrupted Exception e){}
output.println("用户名:"+Username+"
"); 
} 
}
}

  3、避免使用实例变量

  本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。

  修正上面的Servlet代码,将实例变量改为局部变量实现同样的功能,代码如下:

…… 
Public class Concurrent Test extends HttpServlet {public void service (HttpServletRequest request, HttpServletResponse 
Response) throws ServletException, IOException {
Print Writer output; 
String username;
Response.setContentType ("text/html; charset=gb2312");
…… 
} 
}

  对上面的三种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是,如果一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销。SingleThreadModel在Servlet2.4中已不再提倡使用;同样如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。从Java 内存模型也可以知道,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。

 


 

补充:

servlet存在的多线程问题
实例变量:   实例变量是在堆中分配的,并被属于该实例的所有线程共享,所以不是线程安全的. 
JSP系统提供的8个类变量:
JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是线程安全的,APPLICATION在整个系统内被使用,所以不是线程安全的. 
局部变量:   局部变量在堆栈中分配,因为每个线程都有它自己的堆栈空间,所以是线程安全的. 
静态类:       静态类不用被实例化,就可直接使用,也不是线程安全的. 
外部资源:   在程序中可能会有多个线程或进程同时操作同一个资源(如:多个线程或进程同时对一个文件进行写操作).

此时也要注意同步问题. 使它以单线程方式执行,这时,仍然只有一个实例,所有客户端的请求以串行方式执行。这样会降低系统的性能
对于存在线程不安全的类,如何避免出现线程安全问题:
1、采用synchronized同步。缺点就是存在堵塞问题。
2、使用ThreadLocal(实际上就是一个HashMap),这样不同的线程维护自己的对象,线程之间相互不干扰。

 


ThreadLocal的设计 
首先看看ThreadLocal的接口: 
Object get() ; // 返回当前线程的线程局部变量副本 protected Object 
initialValue(); // 返回该线程局部变量的当前线程的初始值                    
void set(Object value); // 设置当前线程的线程局部变量副本的值 
  ThreadLocal有3个方法,其中值得注意的是initialValue(),该方法是一个protected 
的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始 
值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行 
,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null: 
protected Object initialValue() { return null; } 

如果希望线程局部变量初始化其它值,那么需要自己实现ThreadLocal的子类并重写该 
方法,通常使用一个内部匿名类对ThreadLocal进行子类化,比如下面的例子,SerialNum类 
为每一个类分配一个序号: 
public class SerialNum 
{ 
 // The next serial number to be assigned 
 private static int nextSerialNum = 0; 
 private static ThreadLocal serialNum = new ThreadLocal() 
 { 
  protected synchronized Object initialValue() 
  { 
   return new Integer(nextSerialNum++); 
  } 
 };

 public static int get() 
 { 
  return ((Integer) (serialNum.get())).intValue(); 
 } 
}

  SerialNum类的使用将非常地简单,因为get()方法是static的,所以在需要获取当前线 
程的序号时,简单地调用:

int serial = SerialNum.get(); 即可。 
  在线程是活动的并且ThreadLocal对象是可访问的时,该线程就持有一个到该线程局部 
变量副本的隐含引用,当该线程运行结束后,该线程拥有的所以线程局部变量的副本都将失 
效,并等待垃圾收集器收集。 
ThreadLocal与其它同步机制的比较 
  ThreadLocal和其它同步机制相比有什么优势呢?ThreadLocal和其它所有的同步机制都 
是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实 
现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需 
要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该 
对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一 
个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变 
量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有 
必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时 
,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进 
ThreadLocal。 
  由于ThreadLocal中可以持有任何类型的对象,所以使用ThreadLocal get当前线程的值 
是需要进行强制类型转换。但随着新的Java版本(1.5)将模版的引入,新的支持模版参数 
的ThreadLocal<T>类将从中受益。也可以减少强制类型转换,并将一些错误检查提前到了编 
译期,将一定程度地简化ThreadLocal的使用。 
总结 
    当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同 
步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而 
ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量) 
,这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信, 
则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal
,这将极 
大地简化你的程序,使程序更加易读、简洁。

ThreadLocal常见用途:
存放当前session用户
存放一些context变量,比如webwork的ActionContext
存放session,比如Spring hibernate orm的session


例子:用 ThreadLocal 实现每线程 Singleton
        线程局部变量常被用来描绘有状态“单子”(Singleton) 或线程安全的共享对象,或者是通过把不安全的整个变量封装进 ThreadLocal,或者是通过把对象的特定于线程的状态封装进 ThreadLocal。例如,在与数据库有紧密联系的应用程序中,程序的很多方法可能都需要访问数据库。在系统的每个方法中都包含一个 Connection 作为参数是不方便的 — 用“单子”来访问连接可能是一个虽然更粗糙,但却方便得多的技术。然而,多个线程不能安全地共享一个 JDBC Connection。如清单 3 所示,通过使用“单子”中的 ThreadLocal,我们就能让我们的程序中的任何类容易地获取每线程 Connection 的一个引用。这样,我们可以认为 ThreadLocal 允许我们创建每线程单子。
例:把一个 JDBC 连接存储到一个每线程 Singleton 中 
public class ConnectionDispenser { 
  private static class ThreadLocalConnection extends ThreadLocal {
           public Object initialValue() {
                  return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
           }
   }
    private ThreadLocalConnection conn = new ThreadLocalConnection();
    public static Connection getConnection() {
            return (Connection) conn.get();
   }
}

注意:
理论上来说,ThreadLocal是的确是相对于每个线程,每个线程会有自己的ThreadLocal。但是上面已经讲到,一般的应用服务器都会维护一套线程池。因此,不同用户访问,可能会接受到同样的线程。因此,在做基于TheadLocal时,需要谨慎,避免出现ThreadLocal变量的缓存,导致其他线程访问到本线程变量。



文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况 主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。 立即下载

相关推荐

瑞芯微Android固件修改实战:从解包到root提权完整流程(附工具包)

本文详细解析了瑞芯微Android固件深度定制全流程,涵盖从固件包解包、系统镜像修改到植入root提权与分区调整的实战步骤。通过工具链操作与原理剖析,指导开发者安全实现系统精简、权限获取及存储扩容,最终完成固件重新打包与刷机验证,适用于追求设备完全控制权的技术爱好者。

ujm56789012的博客 699

Maven依赖冲突jar包冲突类冲突ServletContext.class

当遇到依赖冲突时应该如何快速排除冲突,希望小伙伴们能赐教

weixin_44765495的博客 6638

信息安全与技术——(十一)恶意代码检测与防范技术

恶意代码(Malicious Code )或恶意软件(Malware )主要是指以危害信息的安全等不良意图为目的的程序,它们一般潜伏在受害计算机系统中实施破坏或窃取信息。

m0_63853448的博客 5991

servlet多线程分析

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,

李爱宝的专栏 670

Crush 终端 LLM 工具安装与使用指南:把 AI 编程助手装进你的命令行

喜欢命令行的开发者需要离线/轻量级 AI 助手的场景希望自定义模型与工具链的高级用户通过LSP + MCP + 多模型支持,Crush 不仅能写代码,还能理解项目、调用工具、连接服务,真正成为你的“终端编程搭档”。

weixin_44058951的博客 1616

Linux内核编程(十三)Input输入子系统

Input 子系统是 Linux 内核中专门为输入设备设计的一个子系统,它提供了一个通用的框架来管理各种输入设备,如键盘、鼠标、触摸屏、游戏手柄等。这个子系统的主要目的是简化和规范化输入设备驱动的开发,同时提高驱动的通用性和兼容性。(1)输入设备:如键盘、鼠标、触摸屏、游戏手柄等,它们是用户与计算机进行交互的主要方式。(2)输入设备驱动的复杂性:传统上,为每种输入设备编写驱动都需要创建文件、进行硬件初始化、实现文件操作函数集和处理中断等。每种设备的驱动可能都有许多重复性的工作。

qq_1033275663的博客 2866

servlet包冲突解决办法

今天用tomcat7.0.53部署了一个应用,这个应用加了一个处理servlet乱码的filter,加完之后一直启动不成功,报错如下: SEVERE: FAIL - Application at context path /redissearch could not be started org.apache.catalina.LifecycleException: Failed to

xiayingwen1989的专栏 2841

鸿蒙系统开发工程师:核心技术解析与深度面试指南

摘要: 鸿蒙系统开发工程师需具备底层驱动开发、系统移植优化及分布式架构能力。核心职责包括硬件适配(Bootloader、内核移植、HDF驱动开发)、性能调优(启动加速、功耗管理)及稳定性保障。技术要求涵盖C/C++编程、Linux内核机制、鸿蒙架构(HDF、分布式服务)及ArkTS/ArkUI基础。面试重点考察系统移植流程(如ARM板适配)、驱动开发(I2C/Display)、性能优化手段及内存/同步机制的应用。

郑伟强dev的专栏 430

web项目中遇到的Maven包依赖冲突问题解决

在搭建web项目时,出现一个比较诡异的问题,任何JSP页面突然都不能够正常地显示,系统爆出HTTP:500(服务器内部错误)的页面 HTTP Status 500 - java.lang.NoSuchMethodError: org.eclipse.jdt.internal.compiler.CompilationResult.getProblems()[Lorg/eclip...

weixin_30448603的博客 373

CMOS图像传感器——工作原理

CMOS图像传感器的曝光与读出

沧海一升的博客 9460

Vue2+OpenLayers动态绘制两个经纬度并计算距离(提供Gitee源码)

动态绘制两个经纬度并计算它们之间的距离。

黄团团的个人博客 366

多个Context启动冲突的问题解决

在Tomcat的server.xml中配置两个context,出现其中一个不能正常启动,交换配置顺序,另一个又不能正常启动,即始终只有第二个配置能启动的情况。如果单独部署,都没有问题。报错大致内容如下:  appears to have started a thread named [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolTh

穿拖鞋写程序 8695

华为OD机试:使用Ascend C语言实现Matmul与LeakyReLU融合算子的全流程设计与优化解析

通过本文的详细解析,相信你已经对华为OD机试中基于Ascend C语言的Matmul+LeakyReLU融合算子的设计与实现有了深入的理解。我们不仅从理论上探讨了融合算子的核心优势,还通过实际的代码示例演示了如何一步步完成算子的实现与优化。融合算子在AI算子开发中的应用,尤其是在处理大规模矩阵计算的场景中,能够显著提升计算效率,优化内存占用,并减少数据传输的开销。通过合理的Tiling策略设计,我们还能够充分利用多核处理器的算力,进一步提升AI模型的训练与推理性能。

qq_38334677的博客 661

【转】 Servlet多线程安全问题

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33918357的博客 80

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

探析以下Servlet的多线程安全问题(转)

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

先相信你自己,然后别人才会相信你。 208

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Servlet多线程安全问题

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

自强 1万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

servlet的多线程与设计线程安全的servlet

servlet的多线程与设计线程安全的servlet

不能说的秘密的博客 1444

servlet多线程问题解决

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

huaguoming的专栏 891

Servlet的线程安全问题

本篇供个人学习使用,有问题欢迎讨论 Servlet的线程安全问题 ​ Servlet 是在单例多线程环境下运行的。其运行可能会出现线程安全问题 一、线程安全问题 1、什么是线程安全问题 同时满足以下两个条件,则会出现线程安全问题: (1)存在多线程并发访问 (2)存在可修改的共享数据 当多个线程同时修改同一个共享数据时,后修改的数据会将先修改的数据覆盖,对数据先进行修改的用户读取到的不是自己修改...

qq_45979254的博客 639

Servlet容器之安全多线程问题

原文地址:http://developer.51cto.com/art/200907/133794.htm   Servlet容器如何实现多线程。其安全的方面又是如何呢?那么本文将就Servlet容器实现多线程给你做简单的介绍。   一,Servlet容器如何同时处理多个请求。 Servlet采用多线程来处理多个请求同时访问,Servelet容器维护了一个线程池来服务请求。 ...

志存高远 180

servlet开发之servlet的线程安全问题

之所以考虑线程安全问题,是因为引入了多线程。多线程指的是这个程序(一个进程)运行时产生了不止一个线程。如果不考虑多线程的话,程序执行只有一条路径,就像人在敲代码的时候只能敲代码,不能戴上耳机听歌。引入多线程,人在敲代码的时候还能听歌,解决一件事情的时候做了另一件事情,效率大大提高了(虽然敲代码的时候听歌不是为了听歌)。用多线程只有一个目的,那就是更好的利用cpu的资源。 Servlet/JSP技...

weixin_40273144的博客 392

servlet如何实现多线程安全??

编写Servlet和JSP的时候,线程安全问题很容易被忽略,如果忽视了这个问题,你的程序就存在潜在的隐患. 1.Servlet的生命周期 Servlet 的生命周期是由Web容器负责的,当客户端第一次请求Servlet时,容器负责初始化Servlet,也就是实例化这个Servlet类.以后这个实例 就负责客户端的请求,一般不会再实例化其他Servlet类,也就是有多个线程在使用这个实例.S

dyf20081124的专栏 319

Servlet线程安全问题学习总结

首先说明的是Servlet不是线程安全的。 Servlet容器在启动或第一次请求这个servlet时,Servlet容器会创建一个Servlet实例。请求完成后,servlet实例会被纳入servlet容器的线程池进行管理。所以在默认情况下,当多个请求是共享一个servlet实例的。因此在多个线程同时访问一个servlet实例时,可能会发生多线程同时访问一个资源的情况,数据可能会变得不

Alex的专栏 973

如何用Synchronied解决Servlet多线程安全问题?

1.用Synchronied解决多线程安全问题: 我们先铺垫Servlet的多线程基础知识。到现在为止,我们所接触到的Servlet都是这样的:第一个人访问Servlet的时候,Servlet会被实例化。之后的人再访问这个Servlet的时候,这个Servlet就不再被实例化了,而是采取线程的模式。用每一个由这个servlet而来的线程来应答来请求的客户。这样的话,Servlet的实例变量,实际...

qq_44594371的博客 186

线程安全与并发安全探究(三)--servlet多线程并发问题

Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。然而,很多人编写Servlet/JSP程序时并没有注意到多线程安全性的问题,这往往造成编写的程序在少量用户访问时没有任何问题,而在并发用户上升到一定值时,就会经常出现一些莫明其妙的问题。   Serv

dongping_share的专栏 528

servlet 多线程问题

介绍了Servlet多线程机制,通过一个实例并结合Java 的内存模型说明引起Servlet线程不安全的原因,给出了保证Servlet线程安全的三种解决方案,并说明三种方案在实际开发中的取舍。   关键字:Servlet 线程安全 同步 Java内存模型 实例变量

1万+
上一篇: 插入排序
下一篇: java多线程
Jmark_GC
博客等级 码龄14年 32粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值