我有一个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;
}
}
流程,并为其添加新流程。但我有问题如何确定它是否仍在运行并在完成后将其从集中删除。所以现在我正在思考迭代运行线程,但完全不知道如何。
答案 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);
}
}
}
}
}