2012-11-13 102 views
0

我在Java中有一個客戶端/服務器應用程序,它們通過serialize/deserialize對象進行通信。通常客戶端發送RequestObj,服務器響應ResponseObj。服務器也發送心跳RequestObj,並且客戶端響應心跳ResponseObj。通過套接字進行Java對象序列化/反序列化緩存

//Sample RequestObj 
public class RequestObj implements Serializable { 
    private static final long serialVersionUID = xxxx; //auto generated 
    int type; //TYPE_HEARTBEAT 
    long time; 
    ... 

    public void setTime() { 
     this.time=System.currentTimeMillis(); 
    } 
} 

當從服務器發送到每個客戶端心臟跳動請求時,它重用相同RequestObj(每個連接),設定與當前的時間,然後發送給客戶端。我期望以正確的時間接收RequestObj。但是,似乎在客戶端反序列化的RequestObj總是給我錯誤的時間。實際上,RequestObj接收到的客戶端與第一個心跳請求對象(RequestObj)完全相同(相同的對象標識/地址)。但在不更新的時間?

//Sample Server side code sending heartbeat 
public class ServerSocketWrapper { 
    Socket socket; 
    ObjectOutputStream oos; 
    ... 
    RequestObj heartbeat = New RequestObj(TYPE_HEARTBEAT); 

    public void sendHeartBeat() { 
     heartbeat.setTime(); 
     logger.info("HeartBeat {} {}", heartbeat.time, formatFullTime(heartbeat.time)); 
     oos.writeObject(heartbeat); 
     oos.flush(); 
    } 
} 

下面是一些示例客戶端代碼:

//Sample Client side code receiving heartbeat 
public class ClientSocketWrapper { 
    Socket socket; 
    ObjectInputStream ois; 
    long heartbeatTime; 
    ... 

    public void run() { 
     while(true) { 
     Object obj = ois.readObject(); 
     if (obj instanceof RequestObj) { 
      RequestObj req = (RequestObj) obj; 
      if (req.type == TYPE_HEARTBEAT) { 
     heartbeatTime = req.time; 
       logger.info("Received heartbeat {} {} {}", heartbeatTime, formatFullTime(heartbeatTime), req); 
       sendResponse(new ResponseObj(req.id, TYPE_HEARTBEAT)); 
      } 
     } 
     ... 
     } 
    } 
} 

這裏是日誌

logs on the server 
16:33:56.186 [pool-2-thread-2] INFO ServerSocketWrapper - HeartBeat 1352842436186 2012-11-13 16:33:56.186 
16:34:56.185 [pool-2-thread-2] INFO ServerSocketWrapper - HeartBeat 1352842496185 2012-11-13 16:34:56.185 
16:35:56.185 [pool-2-thread-1] INFO ServerSocketWrapper - HeartBeat 1352842556185 2012-11-13 16:35:56.185 

logs on the client 
16:34:08.510 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 [email protected] 
16:35:06.758 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 [email protected] 
16:36:10.303 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 [email protected] 

爲什麼在客戶端收到的時間沒有更新? JVM是否在做某種對象緩存?服務器運行w/jdk 1.7.07 64b,而客戶端運行在jdk 1.6.31 64b上。

回答

2

如果使用相同的ObjectOutputStream多次寫入單個對象,則ObjectOutputStream將認識到它已經看到該對象並將其編碼爲對現有對象的引用。這就是序列化如何能夠保持參考別名。

如果你不希望跨消息引用跟蹤,構建一個新的ObjectOutputStreamObjectInputStream對每個新的消息(或#resetObjectInputStreamObjectOutputStream#readUnshared)。如果你不這樣做,但是不要修改和重用消息對象,你不會看到修改的問題,但是你會反過來泄漏資源,因爲ObjectInputStream會對每個對象持有一個強有力的參考它曾經被反序列化。

+0

找到一個鏈接討論相同的問題:http://www.javaspecialists.eu/archive/Issue088.html – fivelements

1

是的,一旦對象通過ObjectOutputStream發送,重新發送它即使被修改,也只會發送對先前發送的對象的引用,除非在流上調用reset()

相關問題