我正在使用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.如何避免线程访问未在其上创建的对象的问题?
谢谢!
答案 0 :(得分:1)
这些是不同的主题。 servlet容器有一个线程池,池中的线程将被分配给http请求。不禁止servlet容器创建给定servlet的多个实例,但通常只有一个。您应该期望从多个线程同时调用servlet。
不要让servlet保持可变状态。在servlet中声明的任何实例变量都应该是Thread安全的。使servlet状态与给定请求相关是必然的麻烦。在方法的局部变量中保持与请求相关的状态。
答案 1 :(得分:1)
- 是Thread [http-nio-8080-exec-8,5,main]和Thread [http-nio-8080-exec-7,5,main]两个不同的线程?
醇>
是的,每个请求都将在另一个线程中运行。
- 在其名称中包含main的线程是否被视为主线程?如果是,那么为什么有多个主线程呢?
醇>
不,只有在JVM启动时创建的初始线程才被视为主线程。任何线程都可以重命名,并在其名称中包含“main”。您在日志中看到的主要部分可能是ThreadGroup
的名称,线程的实际名称是http-nio-8080-exec-7和http-nio-8080-exec-8。
- 如何避免线程访问未在其上创建的对象的问题?
醇>
这并不总是一个问题,在您的情况下发生的是您在Servlet中存储DeviceListRequest
并且通常只有一个Servlet用于多个请求。相反,您应该使用局部变量,如果需要将其传递给方法,或者如果您要将请求转发给另一个Servlet,请将其保存在请求中。
req.setAttribute("someName", new DeviceListRequest());
然后当你想要访问它时:
req.getAttribute("someName");