【问题标题】:What's the best way to implement a list of elements that will have to have elements added/removed from different threads?实现必须从不同线程添加/删除元素的元素列表的最佳方法是什么?
【发布时间】:2018-06-09 04:24:01
【问题描述】:

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

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(而且系统一点也不健壮)。我确信有更好的方法来组织这个混乱。

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

【问题讨论】:

  • 你为什么不使用BlockQueue 实现?
  • 坦率地说,我根本不知道它的存在。我去看看。

标签: java multithreading list


【解决方案1】:

ExecutorService 将很好地满足您的要求。对于每个请求,创建Job,并将其提交给服务。在内部,该服务使用BlockingQueue,这将直接解决您的问题,但您不必担心ExecutorService

具体来说,是这样的:

/* 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();

【讨论】:

    【解决方案2】:

    有几种不同的方法。

    您可以同步列表。这可能是最暴力的方法,但在您迭代插入时仍无助于阻止插入。

    有几个同步的*集合。这些往往更好,但有影响。例如 CopyOnWriteArrayList 将起作用,但它每次都会创建一个新的数组列表(您将分配回变量)。这对于偶尔更新的集合很有用。

    有一个 ConcurrentLinkedQueue——因为它是“链接的”,所以你不能在中间引用一个项目。

    查看“List”接口的实现,然后选择最适合您问题的实现。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 2010-10-13
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多