装饰Java';s可以调用以添加行为

装饰Java';s可以调用以添加行为,java,multithreading,concurrency,threadpool,callable,Java,Multithreading,Concurrency,Threadpool,Callable,让我们假设我们有可能长期运行的任务: public class LongRunningTask { public ReturnType doSomething() { ... } } 我们希望同时运行这些任务中的许多 所以,我有我的电话: public class LongRunningCallable implements Callable<LongRunningTask> { private final LongRunningTask t

让我们假设我们有可能长期运行的任务:

public class LongRunningTask {
    public ReturnType doSomething() {
        ...
    }
}
我们希望同时运行这些任务中的许多

所以,我有我的电话:

public class LongRunningCallable implements Callable<LongRunningTask> {
    private final LongRunningTask task;
    ...
    public ReturnType call() {
        return task.doSomething();
    }
    ...
}
公共类LongRunningCallable实现可调用{
私有最终LongRunningTask任务;
...
公共ReturnType调用(){
返回task.doSomething();
}
...
}
现在,因为这可能会持续很长时间,我不想限制它只运行一定数量。所以,我可能会这样做:

public class InterruptibleCallable<T> implements Callable<T> {
        protected final long timeout;
        protected final TimeUnit timeUnit;
        protected final Callable<T> callable;

        public InterruptibleCallable(long timeout, TimeUnit timeUnit, Callable<T> callable) {
                this.timeout = timeout;
                this.timeUnit = timeUnit;
                this.callable = callable;
        }

        @Override
        public T call() throws Exception {

                ExecutorService executorService = Executors.newSingleThreadExecutor();

                T result = null;

                try {
                    result = executorService.submit(callable).get(timeout, timeUnit);
                } catch (InterruptedException e) {
                    LOGGER.error("Callable: " + callable.toString() + " was interrupted");
                    throw e;
                } catch (ExecutionException e) {
                    throw e;
                } catch (TimeoutException e) {
                    LOGGER.warn("Callable: " + callable.toString() + " timed out after " + timeout + " " + timeUnit);
                    throw e;
                } finally {
                    executorService.shutdown();
                }

                return result;
        }
}
public类interruptablecallable实现可调用{
受保护的最终长超时;
受保护的最终时间单位;
受保护的最终可调用;
public interruptablecallable(长超时、TimeUnit TimeUnit、Callable Callable){
this.timeout=超时;
this.timeUnit=时间单位;
this.callable=可调用;
}
@凌驾
public T call()引发异常{
ExecutorService ExecutorService=Executors.newSingleThreadExecutor();
T结果=null;
试一试{
结果=executorService.submit(可调用).get(超时,时间单位);
}捕捉(中断异常e){
LOGGER.error(“Callable:+Callable.toString()+”被中断”);
投掷e;
}捕获(执行例外){
投掷e;
}捕获(超时异常e){
LOGGER.warn(“可调用:“+Callable.toString()+”在“+timeout+”+timeUnit”之后超时);
投掷e;
}最后{
executorService.shutdown();
}
返回结果;
}
}
这没关系,但现在我还想包装它,以便它在遇到异常时可以重试(延迟):

public class RetryableCallable<T> implements Callable<T> {
    private final long delay;
    private final TimeUnit timeUnit;
    private final Callable<T> callable;

    @Override
    public T call() throws Exception {
        T result = null;

        try {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            result = executorService.submit(this.callable).get();
        } catch (Exception e) {         
            ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
            result = executorService.schedule(this.callable, delay, timeUnit).get();
        }

        return result;
    }
}
public类RetryableCallable实现可调用{
私人最终长时间延迟;
私人最终计时单位;
私人最终可赎回;
@凌驾
public T call()引发异常{
T结果=null;
试一试{
ExecutorService ExecutorService=Executors.newSingleThreadExecutor();
结果=executorService.submit(this.callable.get();
}捕获(例外e){
ScheduledExecutorService executorService=Executors.newSingleThreadScheduledExecutor();
结果=executorService.schedule(this.callable,delay,timeUnit).get();
}
返回结果;
}
}
现在,我的问题是:

  • 是否已经有一个库提供此功能(或超集)

  • 这是一个好的设计吗,特别是创建另一个执行器并在每个包装中提交一个可调用的文件,为什么

  • 从设计模式和性能的角度来看,解决这个问题的最佳方法是什么


  • 谢谢:D

    围绕
    interruptablecallable
    包装
    LongRunningTask
    并在每个
    RetryableCallable
    上创建两个额外的执行器执行错误

    RetryableCallable
    捕获
    TimeoutException
    时,通常不应再次运行相同的任务。这有点让人困惑,因为若任务被超时“杀死”,为什么还要再运行一次呢? 还有,为什么您需要在这里创建另一个执行人?保持简单

    public class RetryableCallable<T> implements Callable<T> {
        private int retries = 3;
    
        @Override
        public T call() throws Exception {
            while (retries-- > 0) {
                try {
                    return callable.call();
                } catch (InterruptedException e) {
                    LOGGER.error("Callable: " + callable.toString() + " was interrupted");
                    throw e;
                } catch (TimeoutException e) {
                    LOGGER.warn("Callable: " + callable.toString() + " timed out after " + timeout + " " + timeUnit);
                    throw e;
                } catch (Exception e) {
                    LOGGER.warn("Callable: " + callable.toString() + " failed");
                }
            }
            throw new IllegalStateException();//or return null
        }
    }
    
    public类RetryableCallable实现可调用{
    私人整数重试次数=3次;
    @凌驾
    public T call()引发异常{
    同时(重试-->0){
    试一试{
    返回callable.call();
    }捕捉(中断异常e){
    LOGGER.error(“Callable:+Callable.toString()+”被中断”);
    投掷e;
    }捕获(超时异常e){
    LOGGER.warn(“可调用:“+Callable.toString()+”在“+timeout+”+timeUnit”之后超时);
    投掷e;
    }捕获(例外e){
    LOGGER.warn(“Callable:+Callable.toString()+”失败);
    }
    }
    抛出新的IllegalStateException();//或返回null
    }
    }
    
    它不应该使用超时和延迟,它是
    RetryableCallable
    但不是
    RetryableCallableWithDelayAndTimeoutAndSomethingElse

    如果您想限制任务的执行时间,我认为至少有4种好方法:

    • 在提交它的线程中调用
      get(time,timeunit)
    • 将任务的执行时间限制在
      call()
      函数中,例如,通过“定期”检查我们是否有更多的时间
    • 创建您自己的executor类,其中包含自定义executor和一个线程审计员,该类将接受一些
      TimeLimitedCallable
      ,它扩展了
      Callable
      ,并具有
      int getTimeLimit()
      函数。审核员将控制所有执行
      TimeLimitedCallable
      的运行任务的时间范围
    • 为“任务的审核员”创建一个单独的执行者,并在将一个(或一组)具有业务逻辑的任务提交到主执行者之后,创建审核员任务并将其提交到单独的执行者

    为什么希望名称中包含“callable”的类创建新的线程池?听起来太复杂了。