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

问题描述:

我正在使用Java中的HttpSevlet构建一个Web服务器。我创建了一个摘要类名为BaseApi它扩展了HttpSevlet并且这作为父类。多线程访问Java中的同一对象

每次doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionBaseApi被调用。实例化新的BaseRequestBaseRequest是我创建的另一个类,它是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方法被称为I THINK,即创建一个新线程。那么,我做了2个并发请求,日志看起来像这样。

[2017-10-18 02:06:39,760] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] retCode:-3 
[2017-10-18 02:06:39,761] INFO Thread:Thread[http-nio-8080-exec-7,5,main] Instance:[email protected] retCode:-3 

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

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

现在,随着代码的继续运行,我注意到线程开始交替访问两个DeviceListRequest。这里的日志

[2017-10-18 02:06:39,760] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] retCode:-3 
[2017-10-18 02:06:39,761] INFO Thread:Thread[http-nio-8080-exec-7,5,main] Instance:[email protected] retCode:-3 
[2017-10-18 02:06:39,765] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] retCode:0 
[2017-10-18 02:06:39,765] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] setResponseObjectWithKey->serverResponse:{"devices":[]} serverResponse_id:636342462 
[2017-10-18 02:06:39,765] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] 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:[email protected] retCode:0 
[2017-10-18 02:06:39,766] INFO Thread:Thread[http-nio-8080-exec-7,5,main] Instance:[email protected] 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:[email protected] serverResponse:{"devices":[],"ret_msg":"OK","ret_code":0} serverResponse_id:1626294887 

的休息再次,只是看在主题:和实例:

在日志的这两条线看看,我表明

[2017-10-18 02:06:39,765] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] setResponseObjectWithKey->serverResponse:{"devices":[]} serverResponse_id:636342462 
[2017-10-18 02:06:39,765] INFO Thread:Thread[http-nio-8080-exec-8,5,main] Instance:[email protected] serverResponse:{"ret_msg":"unknown","ret_code":-3} serverResponse_id:1626294887 

主题螺纹螺纹[HTTP-NIO-8080-EXEC-8,5,主]访问对象DeviceListRequest @ 2f15bbceDeviceListRequest @ 5343acea

注意:顺便说一下,我使用System.identityHashCode(yourObject)来获取对象的ID。我正在使用Thread.currentThread()来获取线程标识符。我的问题如下: 1。是线程[http-nio-8080-exec-8,5,主要]线程[http-nio-8080-exec-7,5,主要]两个不同的线程? 2.包含名称中main的线程是否被认为是主线程?如果是,那么为什么有多个主线程? 3.如何避免线程访问没有创建的对象的问题?

谢谢!

  1. 是线程[HTTP-NIO-8080-EXEC-8,5,主]和线程[HTTP-NIO-8080-EXEC-7,5,主]两个不同的线程?

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

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

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

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

这并不总是一个问题,会发生什么你的情况是,你存储在你的servlet一个DeviceListRequest,通常只有一个被用于多个请求的Servlet。相反,您应该使用本地变量,将其传递给方法(如果需要的话),或者如果您要将请求转发给另一个将其保存在请求中的Servlet。

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

然后当你要访问它以后做:

req.getAttribute("someName"); 

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

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

+0

加一!谢谢(你的)信息! –