0

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) dont call factory method Thread newThread(Runnable r) of ThreadFactory, before that was caused, and its wrong i think, and getQueue() is zero after success submits, also never occur RejectedExecutionException without explicitly creating

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 ?
nnn
  • 23
  • 9
  • 1
    Can you a) clean up the code so only relevant pieces are here and b) rephrase the question. It's all a bit confusing. – Fildor Mar 20 '14 at 13:56

2 Answers2

0

If I understand the question (it's a little bit confusing), it is desirable behaviour - you have a pooled thread, so you don't need to create a new one, and the executor just peeks up the idled thread and reuses it.

Artyomcool
  • 383
  • 2
  • 5
  • >so you don't need to create a new one. yes it`s done by checking getActiveCount() == getCorePoolSize(), but if getActiveCount() == getCorePoolSize() and after cancel one of working task, on submit a new task, factory`s method in ThreadFactory don`t called – nnn Mar 20 '14 at 19:31
  • getActiveCount() return only active threads, but there are also idled. when you cancel the task, one thread becomes idled, so it will be used on the next tasks. – Artyomcool Mar 20 '14 at 19:36
  • but if canceled all tasks and getActiveCount() = 0, on submit a new task, factory`s method don`t called too – nnn Mar 20 '14 at 19:50
  • yep, because you have 4 idled threads in this case. please, read the javadoc, especially keep alive section: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html – Artyomcool Mar 20 '14 at 19:56
  • thanks, how to permanently remove from the queue canceled task(thread), and why getQueue().size() = 0 if active task is working – nnn Mar 20 '14 at 20:00
  • i need call factory`s method on a submit new task for specific named for a new created thread – nnn Mar 20 '14 at 20:04
  • it is removed from the queue. but the thread that was executing the task remains idled until keep alive time you specified in the constructor of executor. maybe you should post another question with your real problem, because that behaviour is the thing ThreadPoolExecutors was designed for: not recreating threads, until you can reuse some of them. – Artyomcool Mar 20 '14 at 20:05
  • @user2728553 Would it suffice to rename the thread? You can use `Thread.currentThread` to get a reference to the thread you are executing on and then you can [set its name](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setName(java.lang.String)). – Fildor Mar 21 '14 at 07:07
0

If you just want to hook the executing of a new task, try to override the beforeExecute method.

Artyomcool
  • 383
  • 2
  • 5