迭代通过ThreadPoolTask​​Executor运行的线程

时间:2016-04-15 08:53:38

标签: java multithreading

我有一个ThreadPoolTaskExecutor,当我创建一个实现Process的{​​{1}}时,我通过Runnable运行它。

现在,在调用executor.execute(process)之前,我想检查execute个对象中的一个字段,并将其与所有其他当前正在运行的进程进行比较,由Process执行。我怎么能这样做,而不是产生并发问题?

代码:

ThreadPoolTaskExecutor

我正在考虑创建简单的public class MyApp { ThreadPoolTaskExecutor executor; //... public void runProcesses { Process firstone = new Process(1); Process nextOne = new Process(1); // iterate through all processes started via executor and currently running, // verify if there is any process.getX() == 1, if not run it executor.execute(firstone ); //wait till firstone will end becouse have the same value of X executor.execute(nextOne); // this cant be perform until the first one will end } } public class Process { private int x; //... public Process (int x){ this.x = x; } public int getX(){ return this.x; } } 流程,并为其添加新流程。但我有问题如何确定它是否仍在运行并在完成后将其从集中删除。所以现在我正在思考迭代运行线程,但完全不知道如何。

2 个答案:

答案 0 :(得分:3)

我认为您最初的想法非常好,并且可以使用不太多的代码。 这将需要一些修补,以便将“已经运行的这个值的Runnable”与“执行此Runnable”分开,但这里有一个粗略的说明并没有注意到这一点:

  • equals()中实施hashCode()Process,以便可以安全地在无序集和地图中使用实例。
  • 创建ConcurrentMap<Process, Boolean>
    • 您不会使用Collections.newSetFromMap(new ConcurrentHashMap<Process, Boolean>)因为您想要使用地图的putIfAbsent()方法。
  • 如果返回的值不是putIfAbsent(),请尝试使用Process每个null添加您要提交的内容并保释。
    • null返回值表示地图中已存在等效Process(因此正在处理中)。
    • 琐碎且不太干净的解决方案是在每个Process实例中为地图注入一个引用,并在putIfAbsent(this, true)方法中执行run()。< / LI>
  • 从中删除已完成处理的每个Process
    • 琐碎且不太干净的解决方案是在每个Process实例中为地图注入一个引用,并remove(this)作为run()方法中的最后一件事。
    • 其他解决方案可以Process实施Callable并返回其唯一值,以便将其从地图中移除,或使用CompletableFuture及其thenAccept()回调。

Here's一个示例,说明了上述简单且不太干净的解决方案(代码太长,无法直接粘贴到此处)。

答案 1 :(得分:1)

虽然@Dimitar为解决这个问题提供了非常好的解决方案,但我想用另一种方法进行补充。

满足您的要求后,您似乎需要保留所有提交的Process es,将它们按x分成不同的队列并逐个执行队列中的进程。

API ThreadPoolExecutor的{​​{1}}授权强化执行者的行为,我参与了ThreadPoolExecutor的以下实施:

    ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<>()) {

    private final ConcurrentMap<Integer, Queue<Runnable>> processes = new ConcurrentHashMap<>();

    @Override
    public void execute(Runnable command) {
        if (command instanceof Process) {
            int id = ((Process) command).getX();
            Queue<Runnable> t = new ArrayDeque<>();
            Queue<Runnable> queue = this.processes.putIfAbsent(id, t);
            if (queue == null) {
                queue = t;
            }
            synchronized (queue) {
                queue.add(command);
                if (!processes.containsKey(id)) {
                    processes.put(id, queue);
                }
                if (queue.size() == 1) {
                    super.execute(queue.peek()); // removal of current process would be done in #afterExecute
                }
            }
        } else {
            super.execute(command);
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (r instanceof Process) {
            int id = ((Process) r).getX();
            Queue<Runnable> queue = this.processes.get(id);
            synchronized (queue) {
                queue.poll(); // remove completed prev process
                Runnable nextProcess = queue.peek(); // retrieve next process
                if (nextProcess != null) {
                    super.execute(nextProcess);
                } else {
                    this.processes.remove(id);
                }
            }
        }
    }
}