繁体   English   中英

多线程访问Java中的同一对象

[英]Multiple threads accessing the same object in Java

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

每次doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException 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方法被称为我认为一个新的线程被创建。 好吧,我发出了2个并发请求,日志看起来像这样。

[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]是两个不同的线程。 因为那里有一个词。 而且我不知道是否可以有两个主线程。 或者,如果这确实是主线程。

因此,基于日志。 我认为有创建两个线程,创建DeviceListRequest @ 2f15bbceDeviceListRequest @ 5343acea DeviceListRequest的两个不同的实例。

现在,随着代码继续运行,我注意到线程开始可互换地访问两个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

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

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

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

谢谢!

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

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

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

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

  1. 是否将名称中包含main的线程视为主线程? 如果是,那么为什么会有多个主线程?

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

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

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

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

然后,当您以后想要访问它时,请执行以下操作:

req.getAttribute("someName");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM