【问题标题】:why is my multi-threaded task not working as it should?为什么我的多线程任务不能正常工作?
【发布时间】:2015-07-29 15:07:06
【问题描述】:

我正在尝试使用批处理操作从 facebook 获取帖子。 我想过让这个任务多线程来加速操作。 基本上,我向 facebook 发送批量请求,在等待响应时,我的任务是做其他需要做的事情。 当我(慢慢地)调试任务时,我得到了我想要测试的 2000 个结果.... 但是当我运行它或让它在请求操作后调试和暂停时,它会小于 2000。

    String[] str = new String[2000];
    ExecutorService exec = Executors.newFixedThreadPool(10);
    List<BatchRequest> request= new CopyOnWriteArrayList<BatchRequest>();
    List <BatchResponse> batchResponses = new ArrayList<BatchResponse>();



    int i=1;
    for(int j=0 ; j<2000; j++) {

        if (i < 50) {
            BatchRequest batch = new BatchRequestBuilder(str[i]).build();
            request.add(batch);
            i++;
            counter++;
        } else {
            i = 1;
            exec.execute(new Runnable() {

                //thread that gets information from facebook into a list of responses
                public void run() {
                    // TODO Auto-generated method stub
                    System.out.println("running");
                    batchResponses.addAll(fc.executeBatch(request));
                    System.out.println("done");

                }

            });
            request.clear();
        }
    }
    exec.shutdown();
    exec.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

我已经删除了所有不必要的东西。希望它仍然有意义。

我的代码有什么问题?

编辑:我编辑了代码以使其更有意义。有人吗?

【问题讨论】:

  • 创建一个示例来说明没有数据库逻辑的相同问题可能会有所帮助(即,而不是 while rs.next() 创建一个迭代 2000 次的循环,而不是创建 batchResponses 数组创建一个字符串数组等)。这将为我们提供可以直接执行和调试的代码,而不必自己进行这些修改来重现您所询问的问题。

标签: java multithreading collections


【解决方案1】:

除了@OldCurmudgeon 的回答,我可以说ArrayList 不是线程安全类。您可以使用其他容器,使用Collections.synchronizedList() 包装它或将同步添加到您的代码中。

还要确保您的 fc 变量引用线程安全类。

【讨论】:

  • 我不明白为什么会出现问题,我没有在线程相关代码附近的任何地方使用 arrayList .... 我只插入它并在代码的末尾移动信息它到数据库。 fc 是来自 restfb 的 DefaultFacebookClient。我不认为它是线程安全的。我如何使其“线程安全”?正如我告诉 OldCurmudgeon 的那样……counter 和 i 没有任何问题。这段代码在慢慢调试时工作得很好,一步一步。
  • 似乎我没有明确表达我的观点。我指出我插入的arrayList 不应该是一个问题,我只是在很久以后才从中获取信息。再一次,剂量似乎是问题所在。我编辑了代码。希望有帮助
  • 您可以从多个不同的线程访问batchResponses。有Java内存模型之类的东西。这是关于 JVM 提供的保证。其中之一是可见性。这是关于在一个胎面中所做的更改从另一个胎面中可见。默认情况下,JVM 不保证可见性。你需要付出特别的努力来实现它。例如使用同步。
  • 我尽我所能。也许我错过了什么?现在,batchResponses 和 request 现在被包裹在 Collections.synchronizedList 和 areCopyOnWriteArrayList.... 但是,代码搞砸了。
【解决方案2】:

counteri 之间的代码似乎有些混淆。也许如果你解释为什么你需要这两个东西会变得更清楚。

就代码而言,主要问题是您永远不会将counter 设置回零。这将导致前 500 个在其自己的线程中作为一批执行,但其余的每个将单独执行。

【讨论】:

  • 计数器仅导致我使用的数据库有 100,000~ 行,我只想测试 500 行。对此没有混淆。正如我所说,如果调试缓慢(只需点击几步),它将正常工作。
【解决方案3】:

一些问题: batchResponses 正在线程内部被访问,并且您正在主线程中推送它。 batchResponses 也不是线程安全的,所以需要同步。

你也在主线程中做 request.clear ......这是一个错误,因为你不能保证新线程已经执行,可能是在你清除它之后新线程运行。新线程会看到 request.size(0) = 0。

主 if 块和 else 块具有相同的线程代码,这有点令人困惑。 if(i== 50) 你进入 else 块并执行请求。 当您的计数器为 500 时,您已经访问了 else 块 10 次,因此您可能有空请求或您插入的最后 50 个。

这段代码有些地方不清楚。

【讨论】:

  • 我知道我的代码有多混乱,但这不是我的代码的最后阶段......当我尝试修复我在这里谈论的错误时,它变得如此混乱。关于具有相同代码的两个块,那是(正如我所说),因为我在我的结果集中的 500 行上运行测试,而不是整个结果集要大得多。关于在线程使用请求时清除请求 - 我在某处读到,只要我使用正确的对象(在本例中为 CopyOnWriteArrayList),如果您认为这是问题所在,那么解决方案是什么?你还有什么建议?
  • 我已经编辑了代码以使其更有意义。请再看看
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-26
  • 1970-01-01
  • 2020-03-18
  • 2022-01-24
  • 2020-04-04
  • 1970-01-01
相关资源
最近更新 更多