[英]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.