我有一个运行线程的队列,并希望在执行时公开它的一些数据,以监控进程。
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();
}
}
答案 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