2016-02-26 79 views
0

明智地創建新對象並使用相同的對象實例而不是創建新對象是明智的。在下面的情況下,我對確定創建對象的解決方案並不十分有信心。有一個SOAP服務類有幾種方法來負責多個客戶。請參閱模板下面,Java設計模式:Factory vs Singleton?在多線程的情況下

Public class SOAPService {   
      public Object getProductList(String CustId, String endPoint){ 
       SOAPStub stub = new SOAPStub(endPoint); 
       Object productList = stub.getProductList(); 
       return productList; 
      } 
      public Object getProductInfo(String CustId, String productId, String endPoint){ 
       SOAPStub stub = new SOAPStub(endPoint); 
       Object productInfo = stub.getProductList(productId); 
       return productInfo; 
      } 
    } 

現在我介紹一個工廠方法爲每個客戶創建對象,並把它放在一個地圖,但我很困惑,當單個客戶的多個線程將訪問該服務類。對象的行爲不會像單身或可能導致任何死鎖問題,或讓線程等待?請在此指導我。

Public class SOAPService { 
     private Map<String, SOAPStub> map = new HashMap<String, SOAPStub>(); 
     public SOAPStub getSOAPObject(String CustId, String endPoint){ 
      if(map.containsKey(CustId)) 
       return map.get(CustId); 
      else{ 
       SOAPStub stub = new SOAPStub(endPoint); 
       map.put(custId, stub); 
       return stub; 
       } 
     } 
     public Object getProductList(String CustId, String endPoint){ 
      SOAPStub stub = getSOAPObject(CustId, endPoint); 
      Object productList = stub.getProductList(); 
      return productList; 
     } 

     public Object getProductInfo(String CustId, String productId, String endPoint){ 
      SOAPStub stub = getSOAPObject(CustId, endPoint); 
      Object productInfo = stub.getProductList(productId); 
      return productInfo; 
     } 
    } 

回答

3

您的HashMap不是線程安全的,它似乎令人懷疑整個路徑你會下降生產力。您的線程可能會花費所有時間阻止訪問共享池,並且隨着負載的增加爭用將變得更糟。儘可能使你的線程獨立於彼此,即使這使得它們使用更多的內存。

一般用於資源密集型對象(如數據庫連接)的預留池。見this question about object pooling。緩存可能對您有所幫助,請查看緩存提供程序,如ehcache。滾動你自己的緩存比你想象的更麻煩。

1

你的第一個代碼示例看起來安全,但..

是的,有服務類單身對象「可以」只有當你有這些正在使用的服務方法的類變量產生問題讀/寫模式。

例如可以採取以下服務方法

private int count = 0; //class variable 

public Response service(Request r) 
{ 
count = r.getSomeVariable(); 
... 
response.setParameter(count); 
} 

上面的方法可能並不安全,因爲每個請求都會有自己的線程,也有着共同的變量「計數」當兩個要求是同時叫他們可能覆蓋彼此的數據。

但如果你在方法本身聲明count爲變量,它將是安全的。因爲每次調用此方法時都會分配一個新的計數變量,這些變量在方法調用結束後將被銷燬。

您可以爲每個安全的請求創建新的服務,但是,這將成爲系統開銷。

0

我建議你作爲標誌。如果由於某種原因想要替換SOAPService的實現,工廠是合適的。因此,signleton實現可能是:

public final class SoapService { 

    public static final String END_POINT = "endpoint"; 

    private final Map<String, InternalSOAPService> map = Collections.synchronizedMap(new HashMap()); 

    // All user services int the box 
    private final Map<String, InternalSOAPService> unmodifiableMap = Collections.unmodifiableMap(someServiceMapInitMethod()); 

    private static SoapService ourInstance = new SoapService(); 

    private SoapService() { 
    } 

    // All user services int the box. No delays. 
    public static InternalSOAPService getServiceFromTheBox(final String custId) { 
     return ourInstance.unmodifiableMap.get(custId);   
    } 

    public static InternalSOAPService getService(final String custId) { 

     InternalSOAPService service = ourInstance.map.get(custId); 

     if (service == null) { 
      synchronized (SoapService.class) { 
       service = ourInstance.new InternalSOAPService(custId); 
       if (service == null) { // Double Checked Locking 
        service = ourInstance.new InternalSOAPService(custId); 
       } 
       ourInstance.map.put(custId, service); 
      } 
     } 
     return service; 
    } 

    public class InternalSOAPService { 

     private final String custId; 

     private final SOAPStub stub; 

     public InternalSOAPService(final String custId) { 
      this.custId = custId; 
      this.stub = new SOAPStub(END_POINT); // Here could be Factory based on custId or END_POINT 
     } 

     public Object getProductList(){ 
      return stub.getProductList(); 
     } 

     public Object getProductInfo(final String productId){ 
      return stub.getProductList(productId); 
     } 
    } 
} 
+0

這是一個很好的解決方案,但是如果同一個對象的兩個線程發送請求 – Bibhaw

+0

請不要延遲響應請擴展您的問題。你認爲可能會延遲到哪裏? –

+0

Eugene,假設我有一個customer_1,其中2個請求線程同時分派,並且假設Thread_1請求正在處理中,並且thread_2將等待對象實例,直到thread_1完成並釋放任務。這就是我想說的對線程2的響應延遲。 但是當我們有一個系統爲每個請求創建對象時,Thread-1和thread_2請求將擁有自己的對象,並且不需要等待釋放該對象。你說的話 ? – Bibhaw

1

明智地創建新對象並使用相同對象 實例而不是創建新對象是明智的。

建議如果性能增益值得誘導的複雜性。就我的經驗而言,在現代面向對象的平臺上很少有這種情況。

您對多線程環境中發生的事情感到困惑,足以表明折衷可能不是有利可圖的。我的注意力:直到你證明樣本#1提出的對象的數量將不可接受地損害了產品的性能,樣本#2是不成熟的優化。