Servlet竞赛

大家好!

我们正在启动Java Developer课程的第七流。 在该课程存在的一年多时间里,它进行了完善,磨练,并添加了一个新的课程,超出了这次。 相同的流程与其余流程的不同之处在于,我们引入了新的步骤系统,将课程分为三个部分,并略微增加了其总持续时间。 因此,现在不必连续五个月就筋疲力尽地获得证书,而可以冷静地选择两个月的时间并接受培训。 但这是歌词,让我们回到本课程启动之前有关各种实用程序的传统。

走吧

1.概述


Java Servlet容器(或Web服务器)是多线程的:对同一个Servlet的多个请求可以同时执行。 因此,在编写servlet时,必须考虑竞争。

如前所述,仅创建一个servlet实例,并且对于每个新请求,Servlet容器都会创建一个新线程来执行servlet的doGet()或doPost()方法。

缺省情况下,servlet不是线程安全的;程序员必须自己照顾这一点。 在本章中,我们将讨论servlet竞争。 这是一个非常重要的概念,因此要重点关注。

2.线程概述




线程是一个轻量级进程,具有自己的调用堆栈,并访问同一进程(共享堆)中其他线程的打开数据。 每个线程都有自己的缓存。

当我们说一个程序是多线程的时,我们的意思是一个对象的同一实例生成多个线程并处理一个代码元素。 这意味着几个连续的控制流将通过同一存储块。 因此,多个线程执行一个程序的一个实例,并因此共享实例变量,并且可能尝试读取和写入这些共享变量。

让我们看一个简单的Java示例。

public class Counter { int counter=10; public void doSomething() { System.out.println(“Inital Counter = ” + counter); counter ++; System.out.println(“Post Increment Counter = ” + counter); } } 

现在,我们创建两个线程Thread1和Thread2来执行doSomething() 。 结果,有可能:

  1. 线程1读取一个计数器值为10
  2. 显示初始计数器= 10,并且将递增
  3. 在线程1递增计数器之前,线程2也会递增计数器,将计数器更改为11
  4. 结果,Thread1的计数器值为10,该值已经过时

在多线程环境(例如servlet)中,这种情况是可能的,因为实例变量由在同一实例中运行的所有线程共享。

3.编写线程安全的servlet


我希望在本节中您将理解我要强调的问题。 如果您有任何疑问,请再次阅读第2点。

在编写servlet时,需要考虑一些要点。

  1. Service()doGet()doPost()或更一般而言, doXXX()方法不应更新或修改实例变量,因为实例变量由同一实例的所有线程共享。
  2. 如果需要修改实例变量,请在同步块中进行修改。
  3. 上述两个规则也适用于静态变量,因为它们也很常见。
  4. 局部变量始终是线程安全的。
  5. 请求和响应对象是线程安全使用的,因为将为servlet中的每个请求以及因此为servlet中运行的每个线程创建一个新实例。

以下是确保线程安全的两种方法:

a)同步您在其中修改实例或静态变量的块(请参见下面的代码片段)。

我们建议您同步代码在其中修改实例变量的块,而不是同步full方法,以提高性能。

注意,我们需要锁定servlet实例,因为我们需要使特定的servlet实例线程安全。

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet { @override public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException int counter; { synchronized (this) { //code in this block is thread-safe so update the instance variable } //other processing; } 

b)单线程模型-实现SingleThreadModel接口以使线程成为单线程,这意味着一次只有一个线程将执行service()或doXXX()方法。 单线程servlet的加载速度较慢,因为新请求必须等待空闲实例被处理

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet implements SingleThreadModel { int counter; // no need to synchronize as implemented SingleThreadModel @override public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } 

不建议使用SingleThreadModel,因为建议使用同步块。

4.结论


在编写servlet时,我们必须非常小心,因为“默认情况下,servlet不是线程安全的”

  1. 如果您的Servlet没有任何静态或成员变量,则不必担心,并且Servlet是线程安全的
  2. 如果您的servlet仅读取实例变量,则您的servlet是线程安全的。
  3. 如果需要更改实例或静态变量,请在同步块中对其进行更新,并保持实例锁定

如果您遵循上述规则,那么下次有人问您:“ Servlet线程安全吗?” -自信地回答:“默认情况下不是,但是,“我的servlet”是线程安全的。

结束

与往常一样,我们在这里等待您的问题,建议等,或者您可以在多线程公开课上询问Sergey Petrelevich。

Source: https://habr.com/ru/post/zh-CN414759/


All Articles