【问题标题】:Recommend a better way to turn synchronous methods to asynchronous in Java推荐一种在Java中将同步方法转为异步的更好方法
【发布时间】:2010-03-11 07:16:16
【问题描述】:

类中有一些同步运行的方法。我希望它们异步运行,第一个想法是包装它,并使用 switch 枚举来决定应该调用哪个函数。但是对于每个调用的方法,我都需要包装类中的一个新方法和一个新的枚举。它看起来像这样:

public class QueuedShow implements InterfaceShowAlert, Runnable {
    private Class Action {
       String param1;
       public static enum ActionEnum{
          NEW, CHECK, UPDATE, DELETE, DISPLAY;
       }
       public ActionEnum todo;
       public Action(ActionEnum todo, Object param){
          this.todo=todo;
          this.param1=param;
       }
    }
    private BlockingQueue<Action> actionList;
    public void run(){
       while(true){
           Action action=actionList.take(); //THIS waits until queue isn't empty
           switch(action.todo){
           case NEW: //Call original function
              ....
           }
       }
    }
    public void new(String param){
       actionList.add(new Action(NEW, param));
    }
}

然后我学会了反思,我有了一个新的想法。那就是使用字符串而不是直接方法调用来调用方法。 包装类读取和解析字符串,并使用反射获取类和包含方法。它将参数和方法对象放入一个类中,该类放入一个队列中。现在该类使用 Method.invoke(params) 而不是使用枚举进行切换。但是这样的问题是编译时类型检查丢失了。

当然,所有这些都只适用于无效的方法,但当然我们也可以使用 Future 类来返回值。

现在有没有任何框架已经实现了将同步调用转换为异步调用,或者你知道有什么其他方法可以做到这一点。

【问题讨论】:

    标签: java asynchronous methods synchronous


    【解决方案1】:

    这是推荐的做法:

    abstract public class Action<T> implements Runnable {
      private final T param;
    
      public Action(T param) {
        this.param = param;
      }
    
      @Override
      public final void run() {
        work(param);
      }
    
      abstract protected void work(T param);
    }
    

    与:

    ExecutorService exec = Executors.newSingleThreadExecutor();
    while (/* more actions need to be done */) {
      exec.submit(action);
    }
    exec.shutdown();
    exec.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
    

    【讨论】:

    • 但这和krosenvoid是一回事,就是说每个方法都需要一个封装类,现在实现一个work(param)方法。
    • @Tians 是的,但它比使用 if 块的 switch 语句调用静态函数更好。它可以很容易地扩展。另外,应该注意的是,您可以将方法直接放在枚举本身上。
    • @cletus,我真正想要的是一种方法,即实现并忘记。相反,这意味着我必须为我想更改为异步的每个方法编写一个包装器。我看了一下Groovy,好像可以用。
    • @Tians 只是创建匿名内部类。这就是 Java 的工作原理。 Swing dev 充满了它们。唯一的选择是对所有内容进行硬编码。匿名内部类真的那么可恶吗?
    • @cletus +1 完全同意你的看法。我写了一个补充你的答案试图说服 OP
    【解决方案2】:

    处理此问题的正常方法是使用 java 5 executors framework,如 here 所示。这将允许您对同步和异步实现使用相同的模式,并且您可以选择使用哪个 ExecutorService。

    【讨论】:

    • 是的,但这意味着你必须为每个方法创建一个新的包装类,实现一个 run() 方法。
    • 是的。大多数人只使用匿名内部类。
    【解决方案3】:

    但那是一回事 krosenvoid,这意味着一个包装器 每个方法都需要类, 现在实现一个 work(param) 方法。

    你要么选择完全动态和反射的东西,你传递String作为方法名称和Object作为参数。因为 Java 是静态类型的(与 Groovy 等动态语言不同),这将是可怕的并且可能充满了强制转换,但你可以做到。

    您当前的解决方案使用enums 列出了异步方法。因此,如果不更改代码,它也不是完全动态的和可扩展的。也就是说,您需要为每个新方法添加一个新的enum

    public static enum ActionEnum{
              NEW, CHECK, UPDATE, DELETE, DISPLAY;
    }
    

    如果你没问题,也可以使用ActionCallable,如其他答案中所建议的那样。对于每个新方法,您都需要编写一个新的ActionCallable,以便静态定义方法调用。

     protected void work(String param)
     {
          myObject.theMethodToDispatch( param );
     }
    

    我同意它是更多样板代码,但这仍然相当小。最大的胜利是你的代码不是反射的(并且不应该有强制转换)并且你有静态类型语言的好处:你可以重构方法名称,如果类型参数不匹配,编译器会警告你等。

    【讨论】:

      猜你喜欢
      • 2010-11-04
      • 1970-01-01
      • 2021-04-12
      • 2019-12-26
      • 2014-01-21
      • 2012-02-04
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      相关资源
      最近更新 更多