0

Facing the problem with the ThreadPoolExecutor in Java.

How can I execute a continuous task using it? For example, I want to execute something like this:

    @Async
    void MyVoid(){
       Globals.getInstance().increment();
       System.out.println(Thread.currentThread().getName()+" iteration # "+ Globals.getInstance().Iterator);
    }

I want it to run forever in 2 parallel asynchronous threads until the user sends a request to stop the ThreadPoolExecutor in the "/stop" controller.

If I use this for example:

    @Controller
    @RequestMapping("api/test")
    public class SendController {

        ThreadPoolExecutor executor =  new ErrorReportingThreadPoolExecutor(5);
        boolean IsRunning = true;

        @RequestMapping(value = "/start_new", method = RequestMethod.POST)
        public Callable<String> StartNewTask(@RequestBody LaunchSend sendobj) throws IOException, InterruptedException {

            Runnable runnable = () -> { MyVoid();};
            executor.setCorePoolSize(2);
            executor.setMaximumPoolSize(2);


            while (IsRunning) {
                executor.execute(runnable);
                System.out.println("Active threads: " + executor.getActiveCount());
            }


            return () -> "Callable result";
        }

        @RequestMapping(value = "/stop", method = RequestMethod.GET)
        public Callable<String> StopTasks()  {
            executor.shutdown(); //for test
            if(SecurityContextHolder.getContext().getAuthentication().getName() != null &&  SecurityContextHolder.getContext().getAuthentication().getName() != "anonymousUser") {
                executor.shutdown();
                return () -> "Callable result good";
            }
            else { return () -> "Callable result bad";}
        }
    }

public class ErrorReportingThreadPoolExecutor extends ThreadPoolExecutor {
    public ErrorReportingThreadPoolExecutor(int nThreads) {
        super(nThreads, nThreads,
                0, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }

    @Override
    protected void afterExecute(Runnable task, Throwable thrown) {
        super.afterExecute(task, thrown);

        if (thrown != null) {
            // an unexpected exception happened inside ThreadPoolExecutor
            thrown.printStackTrace();
        }

        if (task instanceof Future<?>) {
            // try getting result
            // if an exception happened in the job, it'll be thrown here
            try {
                Object result = ((Future<?>)task).get();
            } catch (CancellationException e) {
                // the job get canceled (may happen at any state)
                e.printStackTrace();
            } catch (ExecutionException e) {
                // some uncaught exception happened during execution
                e.printStackTrace();
            } catch (InterruptedException e) {
                // current thread is interrupted
                // ignore, just re-throw
                Thread.currentThread().interrupt();
            }
        }
    }
}

I'm getting the following errors:

  1. As I understood, a lot of tasks got submitted into the 'executor' queue within a few seconds and then the executor handled all them. (But I need each thread to wait before the current task ends and then submit the new one to the executor, I think.)

  2. HTTP Requests to these controllers are forever "IDLE" until the next request comes, i.e. after sending a request to /api/test/start_new the controller's code executed tasks that are running, but the request is IDLE.

How can I do this in Java?

P.S. Spring MVC is used in the project. It has its own implementation of ThreadPoolExecutor - ThreadPoolTaskExecutor, but I am facing similar problems with it.

James Dunn
  • 8,064
  • 13
  • 53
  • 87
user1935987
  • 3,136
  • 9
  • 56
  • 108
  • If you need to know when a task is completed, look at using `java.util.concurrent.Executors` to create an `ExecutorService`. `ExecutorService::submit` will return a `Future` which you can use to tell when a task is completed. If you are using Java 8, also look at `CompletableFuture`, which is a new, nicer interface. – Andrew Rueckert Dec 22 '15 at 20:29
  • Do you mean continuous? or do you mean continual? I would not normally use an `ExecutorService` to run a task that never ends. I would use a naked `Thread` for that. On the other hand, I would use a `ScheduledExecutorService` (or something like it) to continually run a short-lived task at periodic intervals. – Solomon Slow Dec 22 '15 at 20:33
  • Your task object manipulates the executor to which it has been submitted. That sounds like a really Bad Idea---too much coupling between your classes. This seems like an XY problem: http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem What are you _really_ trying to accomplish? – Solomon Slow Dec 22 '15 at 20:38
  • As i said, that i need is to: run the forever-repeating method in multi-threading for on one user-request, finish all threads in other. – user1935987 Dec 23 '15 at 05:03
  • @jameslarge why not? CachedThreadPoolExecutor is a perfect fit for such task. – Antoniossss Dec 23 '15 at 10:42
  • @Antoniossss, I don't know that class, and a google search turns up nothing. Are you talking about the object returned by `ExecutorService.newCachedThreadPool()`? I don't think I would ever use that in real code. I would not use it where I needed a thread pool because there is no way to limit how many simultaneous threads it will create. And, I would not use it to start a permanent thread because, why go through a middle man when it's just as easy to do it yourself? – Solomon Slow Dec 23 '15 at 14:33
  • @jameslarge 1) Yes i was talking about that pool 2) you are not correct because you can set thread max count. You can confirm that if you check what is happening inside `ExecutorService.newCachedThreadPool()`. – Antoniossss Dec 23 '15 at 14:48
  • @Antoniossss, That's undocumented behavior. The declared return type from `ExecutorService.newCachedThreadPool()` is `ExecutorService`, and there is no `setMaximumPoolSize(n)` method declared in that type. If you happen to know that the _actual_ type of the object is `ThreadPoolExecutor` and you cast it at run time, then everything will be fine... Untill the day when somebody tries to deploy your code on a JRE that doesn't work that way. – Solomon Slow Dec 23 '15 at 15:15
  • @jameslarge But i told u to check out the internals of `newCachedThreadPool` and I thought that you will conclude that creating `new ThreadPoolExecutor(0, Integer.MAX_VALUE, (...)` is the way to go - where insteed of Integer.MAX_VALUE you would use thread limit. Here is some SO about this as well http://stackoverflow.com/questions/1800317/impossible-to-make-a-cached-thread-pool-with-a-size-limit – Antoniossss Dec 23 '15 at 15:27

0 Answers0