通过覆盖afterExecute(Runnable r,Throwable t)可以反复的线程池

时间:2016-01-13 09:17:28

标签: java multithreading threadpoolexecutor

我想实现一个线程池,通过覆盖afterExecute钩子可以执行某些任务。我可以再次提交参数Runnable r吗?

这是我的初步实施。

public class RetriableThreadPool extends ThreadPoolExecutor {

  static final int MAXRETRYTIMES = 5;

  int retryTimes = 0;

  public RetriableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
      TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    retryTimes = 0;
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    if (retryTimes < MAXRETRYTIMES) {
      retryTimes++;
      super.submit(r);
    }
  }

}

在这个初始实现中,我只允许提交一个任务。

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {

  public static void main(String[] args) {
    RetriableThreadPool retriableThreadPool = new RetriableThreadPool(10, 10, 0L,
        TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    retriableThreadPool.execute(new Runnable() {
      int num = 0;

      @Override
      public void run() {
        // TODO Auto-generated method stub
        num = num + 123;
        System.out.println(num);
      }

    });
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    // retriableThreadPool.shutdown();
  }
}

在这个例子中,我得到了奇怪的输出:

123
246

如果可以重新提交runnable,我想我应该得到5个输出。如果无法重新提交。结果只有123。我不明白这个输出的原因。

我感谢nogard修改了代码

public class RetriableThreadPool extends ThreadPoolExecutor {

  static final int MAXRETRYTIMES = 5;

  int retryTimes = 0;

  public RetriableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
      TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    retryTimes = 0;
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    if (retryTimes < MAXRETRYTIMES) {
      retryTimes++;
      super.execute(r);
    }
  }
}

我还有其他3个问题:

  1. 如何使用原始状态重试runnable。在这种情况下,我预计结果将是123
  2. 的5倍
  3. 如何为方法submit添加挂钩,就像afterExecute
  4. 一样execute
  5. 是否已经实现了可恢复的线程池?我希望runnable在抛出异常或可调用时返回某些结果时重试。

1 个答案:

答案 0 :(得分:1)

我认为此类行为的原因是您在afterExecute方法中提交任务而不是执行,并且提交不会再次触发afterExecute回调。这就是为什么你在输出中只看到两行:第一行来自原始执行,第二行来自提交。

此外,您永远不会增加重试计数器,您的任务将始终重新提交

@Override
protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    ++ retryTimes;
    if (retryTimes < MAXRETRYTIMES) {
        super.execute(r);
    }
}

更新您的3个问题:

  1. 有多种选择:

    • 不要更改Runnable内的状态(不要分配给num)
    • 创建Runnable(或复制实例)的新实例
    • 重置Runnable的状态
  2. 对于钩子,我会用Decorator模式实现:类似这样:

    public class YourExecutor {
    @Override
    public void submit(Runnable task) {
        return super.submit(new TaskDecorator(task));
    }
    
    protected void onCompletedTask(Runnable task) {
        // callback
    }
    
    private class TaskDecorator implements Runnable {
        private final Runnable delegate;
    
        public TaskDecorator(Runnable delegate) {
            this.delegate = delegate;
        }
    
        @Override
        public void run() {
            this.delegate.run();
            onCompletedTask(delegate);
        }
    }