0

Currently, I'm making sure my tasks have finished before moving on like so:

    ExecutorService pool = Executors.newFixedThreadPool(5);

    public Set<Future> EnqueueWork(StreamWrapper stream) {
        Set<Future> futureObjs = new HashSet<>();
        util.setData(stream);
        Callable callable = util;

        Future future = pool.submit(callable);
        futureObjs.add(future);

        pool.shutdown();
        try {
            pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Node.sendTCP(Node.getNodeByHostname(StorageTopology.getNextPeer()), Coordinator.prepareForTransport(stream));

        return futureObjs;
    }

However, because of some other threading on my socket, it's possible that multiple calls are made to EnqueueWork - I'd like to make sure the calls to .submit have completed in the current thread, without shutting down the pool for subsequent threads coming in.

Is this possible?

MrDuk
  • 16,578
  • 18
  • 74
  • 133
  • If i remember correctly, `.shutdown()` on pool will be completed only after all threads will be completed. – Everv0id Dec 04 '15 at 08:20
  • Thanks, but that's not really an option for me I don't think. I don't want to shut down the pool, and then later have another thread pop in and decide to use the pool that's been shutdown. – MrDuk Dec 04 '15 at 08:23
  • I understood what you want. But i think what you really need is to refactor your multithreading model. – Everv0id Dec 04 '15 at 08:27

4 Answers4

2

You can check by invoking isDone() method on all the Future objects in futureObjs. You need to make sure isDone is called in a loop. calling get() method on Future object is another option, since get() is a blocking call, it will return only after task is completed and result is ready. But do you really want to keep the pool open after all the tasks are done?

akki
  • 423
  • 2
  • 12
0

I agree with one of the comments, it seems odd that your executor can be used by different threads. Usually and executor is private to an instance of some class, but anyhow.

What you can do, from the docs, is to check:

getActiveCount() - Returns the approximate number of threads that are >actively executing tasks.

NOTE: This is a blocking method, it will take out a lock on the workers of your threadpool and block until it has counted everything

And also check:

getQueue() - Returns the task queue used by this executor. Access to the task queue is intended primarily for debugging and monitoring. This queue may be in active use. Retrieving the task queue does not prevent queued tasks from executing.

If your queue is empty and the activeCount is 0, all your tasks should have finished. I say should because getActiveCount says "approximate". Looking at the impl, this is most likely because the worker internally has a flag indicating that it is locked (in use). There is in theory a slight race between executing and the worker being done and marking itself so. A better approach would in fact be to track the features. You would have to check the Queue and that all futures are done.

However I think what you really need is to reverse your logic. Instead of the current thread trying to work out if another thread has submitted work in the meantime, you should have the other thread call isShutdown() and simply not submit a new task in that case.

pandaadb
  • 6,306
  • 2
  • 22
  • 41
  • Sharing an executor makes a lot of sense, especially for generic background tasks. – TwoThe Dec 04 '15 at 10:41
  • At which point you'd probably have a worker Class containing the Executor that receives your background tasks and executes them. Not a publicly available executor that can be accessed by any random piece like a constant surely? – pandaadb Dec 04 '15 at 10:50
0

You have already added Future to the set. Just add below code block to get the status of each Future task by calling get() with time out period.

In my example, time out is 60 seconds. You can change it as per your requirement.

Sample code:

        try{
            for(Future future : futureObjs){
            System.out.println("future.status = " + future.get(60000, TimeUnit.MILLISECONDS));
            }
        }catch(Exception err){
            err.printStackTrace();
        }

Other useful posts:

How to forcefully shutdown java ExecutorService

How to wait for completion of multiple tasks in Java?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

You are approaching this issue from the wrong direction. If you need to know whether or not your tasks are finished, that means you have a dependency of A->B. The executor is the wrong place to ensure that dependency, as much as you don't ask the engine of your car "are we there yet?".

Java offers several features to ensure that a certain state has been reached before starting a new execution path. One of them is the invokeAll method of the ExecutorService, that returns only when all tasks that have been submitted are completed.

pool.invokeAll(listOfAllMyCallables);
// if you reach this point all callables are completed
TwoThe
  • 13,879
  • 6
  • 30
  • 54