如何在ThreadPoolExecutor中访问正在运行的线程?

时间:2016-02-23 07:34:07

标签: java multithreading threadpoolexecutor java-threads

我有一个运行线程的队列,并希望在执行时公开它的一些数据,以监控进程。

ThreadPoolExecutor提供对其队列的访问,我可以遍历这些对象来调用我重写的toString()方法,但这些只是等待执行的线程。

有没有办法访问当前运行的线程来调用我的方法?或者也许总的来说这个任务有更好的方法吗?

为了澄清更多关于目的的内容,这里有一些一般性的代码:

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 +
            '}';
    }
}

和一个持有遗嘱执行人的班级:

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();
   }
}

5 个答案:

答案 0 :(得分:3)

如何将Runnable包装成这样。

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);
    }
}

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();
   }
}

答案 1 :(得分:2)

无论何时向队列添加线程,还要将其添加到第二个数据结构,比如HashSet。然后,如果您需要访问正在运行的线程,您可以检查ExecutorService的队列以查找仍在等待执行的线程:HashSet中的所有线程仍然在ExecutorService中1}}的队列当前正在运行。

答案 2 :(得分:1)

就像我在评论中写的那样。我对共享统计对象方法进行了主动更新:

我改变了这样的任务:

public class GetDataTask implements Runnable {
    private String pageNumber;
    private int dataBlocksParsed;
    private String source;
    private String dataType;
    HashMap<GetDataTask,String> statistics


    public GetDataTask(String source, String dataType, HashMap<GetDataTask,String> statistics) {
        this.source = source;
        this.dataType = dataType;
        this.statistics = statistics;
    }

    @Override
    public void run() {
        // you'll probably want to immediately have stats available:
        statistics.put(this, this.toString());

        //do stuff that affects pageNumber and dataBlocksParsed
        // vv this will probably be inside your "do stuff" loop
        statistics.put(this, this.toString());
        // loop end

        // if you do not want stats of finished tasks, remove "this" here.
    }

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

和经理:

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

    private HashMap<GetDataTask,String> stats = new ConcurrentHashMap<GetDataTask,String>();       

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

    // 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()

        // >>> iterate "stats"'s values to build the info string ...            

        return info.append(executor.toString()).toString();
   }
}

更新

您可以通过迭代Map keys(正在执行的任务)并在其上调用toString来轻松更改该方法以提取信息。这与萨卡的方法非常相似。也许你对他的感觉更舒服。

答案 3 :(得分:1)

由于您可以控制使用的执行程序,因此我会使用ThreadPoolExecutor的{​​{1}}和beforeExecute方法来跟踪正在运行的任务,并使用它来创建afterExecute方法。

getActiveTasks

答案 4 :(得分:0)

您只需要将对正在运行的线程的引用存储在ThreadPoolExecutor内将触发的某个地方,除了其他答案外,这是一个小应用程序的示例,该应用程序每隔1秒钟读取ThreadPoolExecutor内部运行的线程状态直到关机:

package sample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);

        for (int i = 1; i <= 10; i++)
        {
            Task task = new Task("Task " + i);
            executor.execute(task);
        }

        executor.shutdown();

        try {
            while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
                System.out.println("Awaiting completion of threads, threads states: " + Task.getThreadsStateCount());
            }

        } catch (InterruptedException e) {
        }

        System.out.println("Executor shutdown -> " + executor.isShutdown());
    }
}

class Task implements Runnable {

    static final List<Thread> activeTasks = Collections.synchronizedList(new ArrayList<>());
    static final Random r = new Random();

    private String name;

    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("current thread : " + t.getName() + " group " + t.getThreadGroup() + " state " + t.getState());
        activeTasks.add(t);

        try {
            int tries = 0;

            while (tries < 10) {
                int randomNum = r.nextInt(10000);
                // do some expensive computation
                for(int i = 0; i < 4; i++) {
                    isPrime(r.nextLong());
                }

                // now sleep
                Thread.sleep(randomNum);
                tries++;
            }

        } catch (InterruptedException e) {
        }

        System.out.println("completed task for thread : " + t.getName() + " group " + t.getThreadGroup() + " state " + t.getState());
    }

    static boolean isPrime(long n)
    {
        if (n <= 1)
            return false;
        if (n <= 3)
            return true;

        if (n % 2 == 0 || n % 3 == 0)
            return false;

        for (int i = 5; i * i <= n; i = i + 6)
            if (n % i == 0 || n % (i + 2) == 0)
                return false;

        return true;
    }

    public static String getThreadsStateCount() {
        return "NEW: " + getCountThreadsState(Thread.State.NEW) +
                " ,RUNNABLE: " + getCountThreadsState(Thread.State.RUNNABLE) +
                " ,WAITING: " + getCountThreadsState(Thread.State.WAITING) +
                " ,TIMED_WAITING: " + getCountThreadsState(Thread.State.TIMED_WAITING) +
                " ,BLOCKED: " + getCountThreadsState(Thread.State.BLOCKED) +
                " ,TERMINATED: " + getCountThreadsState(Thread.State.TERMINATED);
    }

    public static long getCountThreadsState(Thread.State state) {
        return activeTasks.stream().filter(x -> x.getState() == state).count();
    }
}
  

//打印类似:

     

等待线程完成,线程状态:NEW:0,RUNNABLE:1   ,等待:0,等待等待:9,已阻止:0,已终止:0