实现必须在不同线程中添加/删除元素的元素列表的最佳方法是什么?

时间:2018-06-08 17:56:22

标签: java multithreading list

我目前正在尝试实现一个可以在几个不同线程中运行的系统列表:

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(并且系统不是很强大)。我确信有更好的方法来组织这个混乱。

这样做的正确或更好的方法是什么?

2 个答案:

答案 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。你可能会对那里的东西感到惊讶。