我目前正在尝试实现一个可以在几个不同线程中运行的系统列表:
1)第一个线程正在侦听传入的请求并将它们添加到列表中。
2)为每个执行某些操作的请求创建一个新线程。
3)另一个线程遍历列表,检查每个请求的状态,并在完成后从列表中删除它们。
现在,我可以在下面看到我在非常简化的伪代码中的方式:
private List<Job> runningJobs = new ArrayList<>(); // our list of requests
private Thread monitorThread;
private Runnable monitor = new Runnable() { // this runnable is later called in a new thread to monitor the list and remove completed requests
@Override
public void run() {
boolean monitorRun = true;
while(monitorRun) {
try {
Thread.sleep(1000);
if (runningJobs.size()>0){
Iterator<Job> i = runningJobs.iterator();
while (i.hasNext()) {
try {
Job job = i.next();
if (job.jobStatus() == 1) { // if job is complete
i.remove();
}
}
catch (java.util.ConcurrentModificationException e){
e.printStackTrace();
}
}
}
if (Thread.currentThread().isInterrupted()){
monitorRun = false;
}
} catch (InterruptedException e) {
monitorRun = false;
}
}
}
};
private void addRequest(Job job){
this.runningJobs.add(newJob);
// etc
}
简而言之,Runnable监视器在第三个线程中连续运行;第一个线程偶尔会调用addRequest()。
虽然我当前的实现在某种程度上有效,但是我关注这里的操作顺序以及可能的java.util.ConcurrentModificationException(并且系统不是很强大)。我确信有更好的方法来组织这个混乱。
这样做的正确或更好的方法是什么?
答案 0 :(得分:2)
使用 Parallel.ForEach(Partitioner.Create(0L, SUMTOP), (range) =>
{
long local = 0;
for (long i = range.Item1; i < range.Item2; i++) local += i;
Interlocked.Add(ref sum, local);
});
可以很好地满足您的要求。对于每个请求,请创建ExecutorService
,然后将其提交给服务。在内部,该服务使用Job
,可直接解决您的问题,但您不必担心BlockingQueue
。
具体来说,就像这样:
ExecutorService
答案 1 :(得分:1)
有几种不同的方式。
您可以同步列表。这可能是最强大的力量,但在迭代它时仍然无法阻止插入。
有一些同步的*集合。这些往往更好,但有分歧。例如,CopyOnWriteArrayList可以工作,但每次都会创建一个新的数组列表(您将分配回变量)。这对于偶尔更新的集合很有用。
有一个ConcurrentLinkedQueue - 因为它是“链接”你不能引用中间的项目。
查看“列表”界面的实现,选择最适合您问题的界面。
如果您的问题是队列而不是列表,那么也会有一些实现,并且它们往往更适合这类问题。
一般来说,我的答案是,每次java执行主要版本并检查(至少)新集合时,您应该扫描Javadoc。你可能会对那里的东西感到惊讶。