简体   繁体   English

有限制的ScheduledThreadPoolExecutor的Submit方法在释放完整队列后不要调用ThreadFactory

[英]bounded ScheduledThreadPoolExecutor`s submit method don`t call ThreadFactory after release of a full queue

let corePoolSize = 4, after four calls to the submit(or scheduleAtFixedRate and etc) methods, query filled and the method getActiveCount() returns the correct value 4, after the cancellation working task through future.cancel(true) value decreases in getActiveCount() = 3, but new submit(or scheduleAtFixedRate and etc) don t call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and it s wrong i think, and getQueue() is zero after success submits, also never occur RejectedExecutionException without explicitly creating 让corePoolSize = 4,在四次调用commit(或scheduleAtFixedRate等)方法后,查询已填充,并且方法getActiveCount()返回正确的值4,在通过Future取消工作之后.getActiveCount()中的cancel(true)值减小)= 3,但是新的t call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and it (或scheduleAtFixedRate等) t call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and it问题t call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and itt call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and it是错误的,我认为,成功提交后getQueue()为零,无需显式创建就永远不会发生RejectedExecutionException

public class ScheduledTaskCommandExecutor extends ScheduledThreadPoolExecutor {
  private static final TaskCommandThreadFactory factory;
  private static final ConcurrentSkipListMap<ScheduledFuture, String> activeTask;
  private final Semaphore semaphore;

  static {
    factory = new TaskCommandThreadFactory();
    activeTask = new ConcurrentSkipListMap<>();
  }

  public ScheduledTaskCommandExecutor(int corePoolSize) {
    super(4, factory, new RejectionHandler());
    //setMaximumPoolSize(corePoolSize);
    //allowCoreThreadTimeOut(true);
    semaphore = new Semaphore(corePoolSize);
    setRemoveOnCancelPolicy(true);
    setKeepAliveTime(10, TimeUnit.MILLISECONDS);
  }

  @Override
  protected void beforeExecute(Thread t, Runnable r) {
    super.beforeExecute(t, r);
    activeTask.putIfAbsent((ScheduledFuture) r, t.getName());
    System.out.println(t.getName() + " " + ConsoleProperties.Message.TASK_IS_READY.toString());
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {
    try {
      long endTime = System.nanoTime();
    } finally {
      super.afterExecute(r, t);
      System.out.println(getTaskNameByFuture((ScheduledFuture) r) + " " + ConsoleProperties.Message.TASK_IS_COMPLETED.toString());
      activeTask.remove(r);
      //why getQueue()always empty after execute??
      for(Iterator<Runnable> iterator = getQueue().iterator();iterator.hasNext();) {
        System.out.println(iterator.toString());
      }
      //semaphore.release(1);
      purge();
    }
  }

  @Override
  protected void terminated() {
    try {

    } finally {
      super.terminated();
      System.out.println(ConsoleProperties.Message.EXECUTOR_TERMINATED);
    }
  }

  public TaskCommand execute(TaskCommand command) throws RejectedExecutionException {
    //semaphore.tryAcquire() tried that too
    if(getActiveCount() == getCorePoolSize()) {
      System.out.println(getActiveCount() + " " + getCorePoolSize());
      throw new RejectedExecutionException();
    }
    factory.setCommand(command);
    return command.setFuture(scheduleWithFixedDelay(command, command.getDelay(), command.getWaitInterval(), TimeUnit.MILLISECONDS));
  }

  @Override
  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable runnable, long delay, long period, TimeUnit timeUnit) {
    try {
      return super.scheduleAtFixedRate(runnable, delay, period, timeUnit);
    } catch (RuntimeException e) {
      System.out.println("threadNumber:" + e);
      //todo log
      throw e;
    }
  }

  public boolean cancelTaskByName(String name) {
    if (activeTask.containsValue(name)) {
      for (Map.Entry<ScheduledFuture, String> entry : activeTask.entrySet()) {
        if (name.equals(entry.getValue())) {
          return entry.getKey().cancel(true);
        }
      }
    }
    return false;
  }

  public String getState() {
    StringBuilder ret = new StringBuilder();
    ret.append("task count:").append(getTaskCount()).append("\nactive count:").append(getActiveCount()).append("\n");
    ret.append(Arrays.deepToString(activeTask.values().toArray()) + "\n");
    for (Map.Entry<ScheduledFuture, String> entry : activeTask.entrySet()) {
      ret.append("task " + entry.getValue() + " is done " + entry.getKey().isDone() + "\n");
    }
    //ret.append(Arrays.deepToString(executor.getQueue().toArray()) + "\n");
    return ret.toString();
  }

  private String getTaskNameByFuture(ScheduledFuture task) {
    for (Map.Entry<ScheduledFuture, String> entry : activeTask.entrySet()) {
      if (entry.getKey() == task) {
        return entry.getValue();
      }
    }
    return ConsoleProperties.Error.TASK_NOT_FOUND.toString();
  }

  private static class TaskCommandThreadFactory implements ThreadFactory {
    static final AtomicInteger poolNumber = new AtomicInteger(1);
    final ThreadGroup group;
    AtomicInteger threadNumber = new AtomicInteger(1);
    final String namePrefix;
    private TaskCommand command;

    public void setCommand(TaskCommand command) {
      this.command = command;
    }

    TaskCommandThreadFactory() {
      SecurityManager s = System.getSecurityManager();
      group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
      namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
    }

    //this factory`s method don`t call after release full query
    @Override
    public Thread newThread(Runnable r) {
      int n = threadNumber.getAndIncrement();
      //System.out.println("threadNumber:" + n);
      command.setSerialNumber(n);
      Thread ret = new Thread(group, r, /*namePrefix +*/ command.getName(), 0);
      if (ret.isDaemon()) ret.setDaemon(false);
      if (ret.getPriority() != Thread.NORM_PRIORITY) ret.setPriority(Thread.NORM_PRIORITY);
      ret.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
          //todo log4j
          System.out.println(t.getName() + " : Error: " + e.getMessage());
        }
      });
      System.out.println("command thread number:" + command.getName());
      return ret;
    }
  }

  //and this will never occur this Exception without explicitly creating in  
  //public TaskCommand execute(TaskCommand command) method
  private static class RejectionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
      //todo log4j
      System.out.println(r.toString() + " : Rejected");
      throw new RejectedExecutionException();
    }
  }
}

somewhere in the code later 稍后在代码中的某个地方

ScheduledTaskCommandExecutor exec = new ScheduledTaskCommandExecutor(2);
Future futureOne = exec.execute(Runnable); // called method public Thread newThread(Runnable r) in ThreadFactory
why getQueue().size() is zero ?
getActiveCount() is 1;

Future futureTwo = exec.execute(Runnable); // called public Thread newThread(Runnable r) in ThreadFactory
why getQueue().size() is zero ?
getActiveCount() is 2;

Future futureThree = exec.execute(Runnable); // error because checking in  getActiveCount() == getCorePoolSize(),

up to this point everything is correct

futureOne.cancel(true);
getQueue().size() is still zero;
getActiveCount() is 1;

//again
Future futureThree = exec.execute(Runnable); // why now method newThread(Runnable r) in ThreadFactory has not called ?

如果我理解了这个问题(这有点令人困惑),那么这是可取的行为-您拥有一个池化线程,因此您无需创建一个新线程,而执行者只是窥视空闲线程并重新使用它。

如果您只想钩住新任务的执行,请尝试覆盖beforeExecute方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM