Search code examples
javamultithreadingthreadpoolexecutorjava-threads

How to access running threads inside ThreadPoolExecutor?


I have a queue of running threads and would like to expose some of its data while it is executed, to monitor the process.

ThreadPoolExecutor provides access to its queue and I can iterate through these objects to call my overridden toString() method, but these are only threads that are waiting for execution.

Is there a way to access threads that are currently running to call my method? Or maybe there's a better approach for this task in general?

To clarify a bit more about the purpose, here's some code of general idea:

public class GetDataTask implements Runnable {
    private String pageNumber;
    private int dataBlocksParsed;
    private String source;
    private String dataType;


    public GetDataTask(String source, String dataType) {
        this.source = source;
        this.dataType = dataType;
    }

    @Override
    public void run() {
        //do stuff that affects pageNumber and dataBlocksParsed
    }

    @Override
    public String toString() {
        return "GetDataTask{" +
            "source=" + source +
            ", dataType=" + dataType +
            ", pageNumber=" + pageNumber +
            ", dataBlocksParsed=" + dataBlocksParsed +
            '}';
    }
}

and a class holding the executor:

public class DataParseManager {
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(300));

    public void addParseDataTask(String source, String dataType) {
        executor.execute(new GetDataTask(source, dataType));
    }

    // here's the method that I need
    public String getInfo() {
        StringBuilder info = new StringBuilder();
        //and here's the method that I'm missing - executor.getActiveThreads()
        for (Runnable r : executor.getActiveThreads()) {
            info.append(((GetDataTask) r).toString()).append('\n');
        }
        return info.append(executor.toString()).toString();
   }
}

Solution

  • How about wrap Runnable like this.

    static class MonitorRunnable implements Runnable {
    
        static final List<Runnable> activeTasks = Collections.synchronizedList(new ArrayList<>());
    
        private final Runnable runnable;
    
        public MonitorRunnable(Runnable runnable) {
            this.runnable = runnable;
        }
    
        @Override
        public void run() {
            activeTasks.add(runnable);
            runnable.run();
            activeTasks.remove(runnable);
        }
    }
    

    and

    public class DataParseManager {
        private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(300));
    
        public void addParseDataTask(String source, String dataType) {
            executor.execute(new MonitorRunnable(new GetDataTask(source, dataType)));
        }
    
        // here's the method that I need
        public String getInfo() {
            StringBuilder info = new StringBuilder();
            //and here's the method that I'm missing - executor.getActiveThreads()
            synchronized (MonitorRunnable.activeTasks) {
                for (Runnable r : MonitorRunnable.activeTasks) {
                    info.append(((GetDataTask) r).toString()).append('\n');
                }
            }
            return info.append(executor.toString()).toString();
       }
    }