多个线程在Java中访问同一个对象

时间:2017-10-18 02:42:41

标签: java multithreading servlets

我正在使用Java中的HttpSevlet构建Web服务器。我创建了一个名为 BaseApi 抽象类,它扩展了HttpSevlet,并将其作为父类。

每次调用 BaseApi doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException时。实例化新的 BaseRequest BaseRequest 只是我创建的另一个类,是 BaseApi 的成员。

public abstract class BaseApi extends HttpServlet
{
    private static final long serialVersionUID = 6333682258528494467L;

    protected BaseRequest request;
}

然后我有一个子类, DeviceList 扩展了BaseApi, DeviceListRequest 扩展了 BaseRequest

public class DeviceList extends BaseApi

public class DeviceListRequest extends BaseRequest

问题是这个。每次调用DeviceList的doGet方法时,我 THINK 都会创建一个新线程。好吧,我做了两个并发请求,日志看起来像这样。

[2017-10-18 02:06:39,760] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@2f15bbce retCode:-3
[2017-10-18 02:06:39,761] INFO  Thread:Thread[http-nio-8080-exec-7,5,main] Instance:server.request.DeviceListRequest@5343acea retCode:-3

好吧,不要介意retCode,只关注Thread:Instance:。我不确定Thread[http-nio-8080-exec-8,5,main]Thread[http-nio-8080-exec-7,5,main]是否是两个不同的主题。因为那里有一个单词 MAIN 。我不知道是否可以有两个主线程。或者,如果这真的是主线程。

所以,基于日志。我认为创建了两个线程,并且 DeviceListRequest 的两个不同实例创建了 DeviceListRequest @ 2f15bbce DeviceListRequest @ 5343acea

现在,随着代码继续运行,我注意到Threads开始互换地访问两个 DeviceListRequest 。这是其余的日志

[2017-10-18 02:06:39,760] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@2f15bbce retCode:-3
[2017-10-18 02:06:39,761] INFO  Thread:Thread[http-nio-8080-exec-7,5,main] Instance:server.request.DeviceListRequest@5343acea retCode:-3
[2017-10-18 02:06:39,765] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@2f15bbce retCode:0
[2017-10-18 02:06:39,765] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@2f15bbce setResponseObjectWithKey->serverResponse:{"devices":[]} serverResponse_id:636342462
[2017-10-18 02:06:39,765] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@5343acea serverResponse:{"ret_msg":"unknown","ret_code":-3} serverResponse_id:1626294887
[2017-10-18 02:06:39,766] INFO  Thread:Thread[http-nio-8080-exec-7,5,main] Instance:server.request.DeviceListRequest@5343acea retCode:0
[2017-10-18 02:06:39,766] INFO  Thread:Thread[http-nio-8080-exec-7,5,main] Instance:server.request.DeviceListRequest@5343acea setResponseObjectWithKey->serverResponse:{"devices":[],"ret_msg":"unknown","ret_code":-3} serverResponse_id:1626294887
[2017-10-18 02:06:39,766] INFO  Thread:Thread[http-nio-8080-exec-7,5,main] Instance:server.request.DeviceListRequest@5343acea serverResponse:{"devices":[],"ret_msg":"OK","ret_code":0} serverResponse_id:1626294887

再次,看看Thread:和Instance:

从我展示的内容中看看这两行日志

[2017-10-18 02:06:39,765] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@2f15bbce setResponseObjectWithKey->serverResponse:{"devices":[]} serverResponse_id:636342462
[2017-10-18 02:06:39,765] INFO  Thread:Thread[http-nio-8080-exec-8,5,main] Instance:server.request.DeviceListRequest@5343acea serverResponse:{"ret_msg":"unknown","ret_code":-3} serverResponse_id:1626294887

线程线程:线程[http-nio-8080-exec-8,5,main] 访问对象 DeviceListRequest @ 2f15bbce DeviceListRequest @ 5343acea

注意:顺便说一句,我使用System.identityHashCode(yourObject)来获取对象的ID。我正在使用Thread.currentThread()来获取线程标识符。

我的问题如下: 1. 线程[http-nio-8080-exec-8,5,主要] 线程[http-nio-8080-exec-7,5,主要] 两个不同的线程? 2.在其名称中包含main的线程是否被视为主线程?如果是,那么为什么有多个主线程呢? 3.如何避免线程访问未在其上创建的对象的问题?

谢谢!

2 个答案:

答案 0 :(得分:1)

这些是不同的主题。 servlet容器有一个线程池,池中的线程将被分配给http请求。不禁止servlet容器创建给定servlet的多个实例,但通常只有一个。您应该期望从多个线程同时调用servlet。

不要让servlet保持可变状态。在servlet中声明的任何实例变量都应该是Thread安全的。使servlet状态与给定请求相关是必然的麻烦。在方法的局部变量中保持与请求相关的状态。

答案 1 :(得分:1)

  
      
  1. 是Thread [http-nio-8080-exec-8,5,main]和Thread [http-nio-8080-exec-7,5,main]两个不同的线程?
  2.   

是的,每个请求都将在另一个线程中运行。

  
      
  1. 在其名称中包含main的线程是否被视为主线程?如果是,那么为什么有多个主线程呢?
  2.   

不,只有在JVM启动时创建的初始线程才被视为主线程。任何线程都可以重命名,并在其名称中包含“main”。您在日志中看到的主要部分可能是ThreadGroup的名称,线程的实际名称是http-nio-8080-exec-7和http-nio-8080-exec-8。

  
      
  1. 如何避免线程访问未在其上创建的对象的问题?
  2.   

这并不总是一个问题,在您的情况下发生的是您在Servlet中存储DeviceListRequest并且通常只有一个Servlet用于多个请求。相反,您应该使用局部变量,如果需要将其传递给方法,或者如果您要将请求转发给另一个Servlet,请将其保存在请求中。

req.setAttribute("someName", new DeviceListRequest());

然后当你想要访问它时:

req.getAttribute("someName");