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

Java 什么';实现必须从不同线程添加/删除元素的元素列表的最佳方法是什么?,java,multithreading,list,Java,Multithreading,List,我目前正在尝试实现一个系统列表,该列表将在几个不同的线程中运行: 1) 第一个线程正在侦听传入的请求并将它们添加到列表中 2) 为每个请求创建一个新线程来执行某些操作 3) 另一个线程遍历列表,检查每个请求的状态,并在请求完成后将其从列表中删除 现在,我在一个非常简化的伪代码中的方式可以在下面查看: private List<Job> runningJobs = new ArrayList<>(); // our list of requests private Thr

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

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
}
private List runningJobs=new ArrayList();//我们的请求清单
私有线程监控线程;
private Runnable monitor=new Runnable(){//稍后在新线程中调用此Runnable以监视列表并删除已完成的请求
@凌驾
公开募捐{
布尔monitorun=true;
while(monitorun){
试一试{
睡眠(1000);
if(runningJobs.size()>0){
迭代器i=runningJobs.Iterator();
while(i.hasNext()){
试一试{
Job=i.next();
如果(job.jobStatus()==1){//如果作业已完成
i、 删除();
}
}
catch(java.util.ConcurrentModificationException e){
e、 printStackTrace();
}
}
}
如果(Thread.currentThread().isInterrupted()){
monitorRun=false;
}
}捕捉(中断异常e){
monitorRun=false;
}
}
}
}; 
私有无效添加请求(作业){
this.runningJobs.add(newJob);
//等
}
简而言之,Runnable监视器是在第三个线程中连续运行的监视器;第一个线程偶尔调用addRequest()

虽然我当前的实现在某种程度上是可行的,但我关心的是这里的操作顺序和可能的java.util.ConcurrentModificationException(而且系统并不健壮)。我确信有更好的方法来组织这场混乱


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

有几种不同的方法

您可以同步列表。这可能是最残酷的暴力行为,在您迭代插入时仍然无法阻止插入

有几个已同步的*集合。这些措施往往更好,但也会产生影响。例如,CopyOnWriteArrayList可以工作,但它每次都会创建一个新的数组列表(您可以将其分配回变量)。这适用于偶尔更新的集合

有一个并发链接队列,因为它是“链接”的,不能在中间引用一个项目。

查看“列表”接口的实现,并选择最适合您的问题的实现

如果您的问题是队列而不是列表,那么也有一些实现,它们往往更适合于这种类型的问题


一般来说,我的答案是,您可能应该在每次java发布主要版本时扫描Javadocs,并检查(至少)新集合。你可能会对里面的东西感到惊讶。

有几种不同的方式

您可以同步列表。这可能是最残酷的暴力行为,在您迭代插入时仍然无法阻止插入

有几个已同步的*集合。这些措施往往更好,但也会产生影响。例如,CopyOnWriteArrayList可以工作,但它每次都会创建一个新的数组列表(您可以将其分配回变量)。这适用于偶尔更新的集合

有一个并发链接队列,因为它是“链接”的,不能在中间引用一个项目。

查看“列表”接口的实现,并选择最适合您的问题的实现

如果您的问题是队列而不是列表,那么也有一些实现,它们往往更适合于这种类型的问题


一般来说,我的答案是,您可能应该在每次java发布主要版本时扫描Javadocs,并检查(至少)新集合。您可能会对其中的内容感到惊讶。

使用
Executor服务可以很好地满足您的需求。对于每个请求,创建
作业
,并将其提交给服务。在内部,该服务使用
阻塞队列
,可以直接解决您的问题,但您不必担心
执行器服务

具体来说,是这样的:

/* At startup... */
ExecutorService workers = Executors.newCachedThreadPool();

/* For each request... */
Job job = ... ;
workers.submit(job); /* Assuming Job implements Runnable */
// workers.submit(job::jobEntryPoint); /* If Job has some other API */

/* At shutdown... */
workers.shutdown();

Executor服务将很好地满足您的需求。对于每个请求,创建
作业
,并将其提交给服务。在内部,该服务使用
阻塞队列
,可以直接解决您的问题,但您不必担心
执行器服务

具体来说,是这样的:

/* At startup... */
ExecutorService workers = Executors.newCachedThreadPool();

/* For each request... */
Job job = ... ;
workers.submit(job); /* Assuming Job implements Runnable */
// workers.submit(job::jobEntryPoint); /* If Job has some other API */

/* At shutdown... */
workers.shutdown();

为什么不使用实现呢?坦白说,我根本不知道它的存在。我来看看。你为什么不使用一个实现呢?坦白说,我根本不知道它的存在。我来看看。