【问题标题】:Java Static Factory conversionJava 静态工厂转换
【发布时间】:2012-09-05 19:13:54
【问题描述】:

在我的客户端/服务器桌面应用程序上。我有这个问题,我应该如何使用我的模型正确编码我的 JDBC 类,以确保所有持久性请求都可以支持并发。 i.e., multiple models want to request update to its persistence counterpart simultaneously [without atmost delay].

剧情是这样的。遵循位于服务器应用程序中的类。

持久性包:

abstract class AbstractService {
  // other fields
  private final String tName, tId;
  private final String sqlStatement;
  public AbstractService(final String tName, final String tId) {
    this.tName = tName;
    this.tId = tId;
    this.sqlStatement = ""; // SELECT statement
  }
  // java.sql.Connection() createConnection()
  // methods
}
public class T1Service extends AbstractService {
  private final String sqlDMLStatements;
  public T1Service() {
    super("t1", "t1Id");
    this.sqlDMLStatements = ""; // other DML statements
  }      
  // methods having return types of List<E>, Object, Boolean, etc.
  // i.e., public List<E> listAll()
}

通信类[客户端类]

import java.net.*;
import java.io.*;
public class Client extends Observable{
  private Socket socket;
  private ObjectInputStream input;
  private ObjectOutputStream output;
  private Object message;
  // Constructor
  // Getters/Setters
  // Other methods like open or close input/output
  private class ReceiverRunnable implements Runnable
    @Override
    public void run() {
       while(running) { // if socket is still open and I/O stream are open/initialized
          try { message = input.readObject(); } 
          catch(Exception e) {}
          finally { setChanged(); notifyObservers(); }  
       } 
    }
  }
}

主类[服务器类]

import java.net.*;
public class Server {
   private List<Client> clientList; // holds all active connections with the server
   private T1Service    t1Service
   private class ConnectionRunnable implements Runnable {
      @Override public void run() {
         while(running) { // serverSocket is open
           Client client = new Client(ServerSocket.accept(), /* other parameters */);
           client.addObserver(new ClientObserver(client));
           clientList.add(client);
         }
      } 
   }
   private class ClientObserver implements Observer {
      private Client client;
      // Constructor
      public void update(Observable o, Object arg) {
         // Check the contents of 'message' to determine what to reply
         // i.e., message.equals("Broadcast") {
         // synchronized(clientList) {
         //   for(Client element : clientList) {
         //     element.getOutput().writeObject(replyObject);
         //     element.getOutput()..flush();
         //   }
         // }
         // i.e., message.equals("T1") {
         // synchronized(t1Service) {
         //     client.getOutput().writeObject(t1.findAll());
         //     client.getOutput().flush();
         // }
      } 
   } 
}

由于这是一个客户端/服务器应用程序,来自客户端的多个请求同时馈送到服务器。服务器处理请求,将适当的回复发送给适当的客户端。 注意:客户端和服务器之间发送的所有对象都是 java.io.Serializable 的实例。

遇到这种情况并查看Server.ClientServer.update() 的块,我们可能会遇到性能问题,或者我应该说由于Intrinsic Locks 而导致处理N 个客户端请求的延迟。但是由于我必须遵守规则 concurrencysynchronization 以确保 Server.T1Service 不会对 N 个客户端请求的队列感到困惑。以下是问题:

  1. 根据Effective Java - Second Edition 中关于Static Factory 的第1 项,这是否可以让我创建一个对Persistence 包类中的方法的新类引用?
  2. List&lt;Client&gt; 中的每个 Client 元素是否会形成并发问题,让 N 个客户端更新它们的 message 字段同时触发 ClientObsver.update(),其中此观察者的引用对象只是父类。 由于内存问题,我避免创建多个 T1Service 实例。
  3. 如果我们要按照 Effective Java - Second Edition 的内容,我如何将我的持久性类转换为易于阅读、易于实例化并支持并发的方式?

【问题讨论】:

  • 要清楚,T1Service.update() 方法中是否有状态正在修改?如果并发调用方法时类中没有状态发生变化,则不存在线程安全问题。
  • 我预见到的并发问题是T1Service.update() 在 2 个或更多客户端更新时触发。我忘记添加有关List&lt;E extends java.util.Observable&gt; 的信息包含java.io.Sockets。 E 是什么,它拥有 Socket、I/O 流以及最重要的来自 java.io.ObjectInputStream.readObject()java.lang.Object message。当java.io.ObjectInputStream.readObject() 收到一个新对象时,会调用java.util.Observable.setChanged()java.util.Observable.notifyObservers()
  • 这里的详细程度尚不清楚 - List 是 update() 方法的参数,还是服务类的字段?向我们展示示例方法签名和类定义会容易得多。
  • List 是服务类中方法的返回类型。 List&lt;E&gt; 其中E 是一个域。
  • 我已经用 Server.ClientObserver.update() 方法中特别发现的可能并发问题/性能问题的详细信息部分更新了我的问题。

标签: java concurrency static-methods static-factory


【解决方案1】:

您可能还想查看演员,例如Akka 中的演员

actor 的基本思想是完全避免同步,使用发送事件。 Akka 将保证一个参与者永远不会被两个线程并行调用。所以你可以定义actor,它对全局变量做一些事情,然后简单地向它发送消息。

通常像魅力一样工作:)

【讨论】:

  • 我不确定这是否会有所帮助。虽然我正在处理 N 个参与者,其中参与者是客户端/服务器模式中的客户端。当您提到一个actor永远不会被两个线程并行调用时,我看不到与我的问题的关系。
【解决方案2】:

我的 [Item 1] 静态工厂理论正确吗?

是的,您可以使用静态工厂代替构造函数。通常这是当您的构造逻辑很复杂并且在各种子类型之间共享以保证工厂模式时。此外,工厂可以提供在 DI 框架之外进行依赖注入的方法。

那它会解决转换后的静态工厂全局对象的并发问题吗?

如果您需要同步构造,那么静态工厂效果很好,只需在工厂方法的方法声明中添加synchronized。如果您需要同步对象本身的方法,那么这将无济于事。

如果在哪里处理对全局对象的并发访问,并且在哪里需要实时访问每个全局对象的方法,我是否建议转换为静态工厂?

正如我上面回答的那样,这取决于您要达到的目标。对于构造函数同步,请使用工厂。

【讨论】:

  • 第三个问题可能会返回List&lt;E&gt;,但因为我们可能不知道其中的元素数量。这可能会导致性能问题,因此,如果我将 synchronized 添加到子类的每个方法中,则会延迟锁定。
  • construction logic 是什么意思?你是关于创建 E 还是 List
  • 构建逻辑是指构建有效对象所涉及的代码,包括任何参数的验证/操作。为什么要加锁,并发修改了什么?
  • 我不一定需要锁定或锁定全局对象中的方法。可能会有两个或多个客户端更新他们的消息对象的情况,我将根据消息确定要调用的全局对象和方法。让我担心的是,当两个或多个客户端向服务器发送类似的请求时。服务器将对请求进行排队,以避免同时请求调用特定方法。
  • 问题是当两个或多个Client 请求排队以便确定哪个将访问全局对象中的方法时。我想要发生的是,当Client(s) 发送相同类型的请求时,我们将以某种方式删除队列,该过程也将同时完成,因此也同时将它们作为来自Server 的回复发送到Client发送的请求。
猜你喜欢
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
相关资源
最近更新 更多