【问题标题】:Java Code Design Using ExecutorService That Calling Mutliple ServicesJava代码设计使用调用多个服务的ExecutorService
【发布时间】:2017-02-22 11:07:32
【问题描述】:

我正在尝试并行运行 15 项服务,每项服务都会向不同的客户群发送邮件。提取标准因每个服务而异

服务 1、服务 2、服务 3.... 服务 15。每个类都扩展了 NotificationService 类。

NotificationService 类有方法 extractRecipients()、sendMail()、sendSMS()、logNotification()。

所有服务类[1 到 15] 都有 process() 方法,该方法将调用 NotificationService 方法并完成它们的工作。

这是设计java代码的正确方法吗?

而且下面的代码看起来很难看,有什么聪明的方法来处理。请有人帮助我。

public void startService() {

try {
    ExecutorService service = Executors.newFixedThreadPool(3);

    for (;;) {
        service.submit(new Service1(conn) {
                    public Object call(){
                        try {
                            process(conn, param2); // Passing connection & obj
                        } catch (Exception e) {
                            throw e;
                        }
                        return null;
                    }
                });

        service.submit(new Service2(conn) {
                    public Object call(){
                        try {
                            process(conn, param2);
                        } catch (Exception e) {
                            throw e;
                        }
                        return null;
                    }
                });

        // like above i have 15 services. so its ugly.
    }

} catch (InterruptedException e) {
    e.printStackTrace();
}
}

public boolean process(Connection conn) throws Exception {
try {
// getRecipientsList(serviceID);

// sendMail(recipientsList);

// logNotificationDetails(notificationList);
} catch (Exception e) {
}
}

【问题讨论】:

  • 当您有相同的任务(电子邮件)要执行时,为什么要提供不同的服务?
  • 15 封电子邮件?给同一个客户?多么烦人。我建议使用一些逻辑来组合它们。我还将服务操作与发送电子邮件分开。使它成为一个单独的步骤。它们不应扩展 NotifyingService。
  • 每个服务类[Service1-15] 都会调用自己的sql并提取收件人。所以15个子类和一个父类..
  • 为了可重用性,我编写了 extractRecipients()、sendMail()、sendSMS()、logNotification() 等方法。因为它对所有服务都是通用的。
  • 15 封电子邮件未发送给同一客户。例如。不同的客户有不同的提取标准。提取标准将因每个服务类别而异。

标签: java executorservice


【解决方案1】:

一些需要改进的地方(不完整):

我假设 Service1、Service2、... 类是从 NotificationService 派生的,覆盖了 process 方法。

匿名接口实现Callable<Object>

service.submit(new Service1(conn) {
                public Object call(){
                    try {
                        process(conn, param2); // Passing connection & obj
                    } catch (Exception e) {
                        throw e;
                    }
                    return null;
                }
            });

应该移到 NotificationService 类。然后这段代码简化为:

service.submit(new Service1(conn)); // Will call Service1's "process" implementation
service.submit(new Service2(conn)); // Will call Service2's "process" implementation
...

编辑:

我想到的是这个设置:

abstract class NotificationService implements Callable<Object>{
  // ...

  // I don't know what types conn and param2 are, so ...
  protected abstract void process( ConnType conn, Param2Type param2 );

  @Override
  public Object call(){
      try {
              process(conn, param2); // Passing connection & obj
      } catch (Exception e) {
              throw e;
      }
      return null;
  }
}

然后您可以覆盖 Service1、Service2 ... 中的 process 以按照特定方式处理流程。

class Service1 extends NotificationService{
    @Override
    protected void process( ConnType conn, Param2Type param2 ){
        // do process according to Service1's needs.
    }
}

无限循环:

for(;;){
   service.submit(...
}

将在该循环中阻止startService 的调用者,同时将新任务添加到执行程序永远

如果每次执行都会向客户发送一封电子邮件,那么他已经被淹没了。


每分钟拨打startService

将产生一个新的 ExecutorService,每分钟无休止地充斥任务!

这不仅会向您的客户发送垃圾邮件,还会很快降低性能。


首先,你可以这样改变:

public void startService() {

try {
    ExecutorService service = Executors.newFixedThreadPool(3);


        service.submit(new Service1(conn)); // assuming callable impl is moved

        service.submit(new Service2(conn));

        // like above i have 15 services. so its ugly.
    service.shutdown();

} catch (InterruptedException e) {
    e.printStackTrace();
}
}

另一种方法是使用 one ScheduledExecutorService,您可以在该服务上安排每个服务N 每分钟执行一次。

【讨论】:

  • 你说callable impl应该移动到process方法,process方法应该在NotificationService中。
  • 没有。 call() 应该在 NotificationService 中。您的 ServiceN 类仍然需要覆盖 process 方法以具有不同的实现。
  • Fildor,请看我下面的答案。这样就可以了。
  • 好的 Fildor,那我的旧代码和你说的一样。我在 ServiceN 类中有调用和处理方法并传递参数 new Service1(conn, param2)
  • Fildor,请看我上面的处理方法。
【解决方案2】:

使用执行器服务的invokeAll。

【讨论】:

  • 能否详细说明一下。
【解决方案3】:
public void startService() {

try {
    List<Bean> list = getServicesNotificationList();

    ExecutorService service = Executors.newFixedThreadPool(list.size); here list size should be 15

    for (int i=0; i < list.size(); i++) {

        service.submit(new NotificationService(conn, list[i]));
    }

    service.shutdown();

} catch (InterruptedException e) {
    e.printStackTrace();
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多