Java设计模式:Factory vs Singleton?在多线程的情况下
明智地创建新对象并使用相同的对象实例而不是创建新对象是明智的。在下面的情况下,我对确定创建对象的解决方案并不十分有信心。有一个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;
}
}
您的HashMap不是线程安全的,它似乎令人怀疑整个路径你会下降生产力。您的线程可能会花费所有时间阻止访问共享池,并且随着负载的增加争用将变得更糟。尽可能使你的线程独立于彼此,即使这使得它们使用更多的内存。
一般用于资源密集型对象(如数据库连接)的预留池。见this question about object pooling。缓存可能对您有所帮助,请查看缓存提供程序,如ehcache。滚动你自己的缓存比你想象的更麻烦。
你的第一个代码示例看起来安全,但..
是的,有服务类单身对象“可以”只有当你有这些正在使用的服务方法的类变量产生问题读/写模式。
例如可以采取以下服务方法
private int count = 0; //class variable
public Response service(Request r)
{
count = r.getSomeVariable();
...
response.setParameter(count);
}
上面的方法可能并不安全,因为每个请求都会有自己的线程,也有着共同的变量“计数”当两个要求是同时叫他们可能覆盖彼此的数据。
但如果你在方法本身声明count为变量,它将是安全的。因为每次调用此方法时都会分配一个新的计数变量,这些变量在方法调用结束后将被销毁。
您可以为每个安全的请求创建新的服务,但是,这将成为系统开销。
我建议你作为标志。如果由于某种原因想要替换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);
}
}
}
明智地创建新对象并使用相同对象 实例而不是创建新对象是明智的。
建议如果性能增益值得诱导的复杂性。就我的经验而言,在现代面向对象的平台上很少有这种情况。
您对多线程环境中发生的事情感到困惑,足以表明折衷可能不是有利可图的。我的注意力:直到你证明样本#1提出的对象的数量将不可接受地损害了产品的性能,样本#2是不成熟的优化。
这是一个很好的解决方案,但是如果同一个对象的两个线程发送请求 – Bibhaw
请不要延迟响应请扩展您的问题。你认为可能会延迟到哪里? –
Eugene,假设我有一个customer_1,其中2个请求线程同时分派,并且假设Thread_1请求正在处理中,并且thread_2将等待对象实例,直到thread_1完成并释放任务。这就是我想说的对线程2的响应延迟。 但是当我们有一个系统为每个请求创建对象时,Thread-1和thread_2请求将拥有自己的对象,并且不需要等待释放该对象。你说的话 ? – Bibhaw