[英]Multiple threads accessing the same object in Java
我正在使用Java中的HttpSevlet
构建Web服务器。 我创建了一个名为BaseApi的ABSTRACT类,该类扩展了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 @ 2f15bbce和DeviceListRequest @ 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 @ 2f15bbce和DeviceListRequest @ 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状态与给定请求相关必然会带来麻烦。 将与请求相关的状态保留在方法的局部变量中。
- 线程[http-nio-8080-exec-8,5,main]和线程[http-nio-8080-exec-7,5,main]是两个不同的线程吗?
是的,每个请求都将在不同的线程中运行。
- 是否将名称中包含main的线程视为主线程? 如果是,那么为什么会有多个主线程?
不,只有在JVM启动时创建的初始线程才被视为主线程。 任何线程都可以重命名并在其名称中包含“ main”。 您在日志中看到的主要名称可能是ThreadGroup
的名称,实际的线程名称是http-nio-8080-exec-7和http-nio-8080-exec-8。
- 如何避免有线程访问未在其上创建的对象的问题?
这并不总是一个问题,在您的情况下,您会在DeviceListRequest
中存储一个DeviceListRequest
,并且通常只有一个Servlet用于多个请求。 相反,您应该使用局部变量,如果需要,或者如果您要将请求转发到另一个Servlet,则将其传递给方法,然后将其保存在请求中。
req.setAttribute("someName", new DeviceListRequest());
然后,当您以后想要访问它时,请执行以下操作:
req.getAttribute("someName");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.