是一个"线程链"这个Java应用程序的错误解决方案是什么?

时间:2015-07-07 09:28:47

标签: java multithreading file-io

我正在运行一个程序,我下载大文件,解析它们,然后将我从文件中提取的数据写入另一个文件。

文件需要很长时间才能下载和解析,但写入任务平均只需要一分钟左右。我把它放在一起的解决方案是有三个三线程的fixedthreadpool。

ExecutorService downloadExecutor = Executors.newFixedThreadPool(3);
ExecutorService parseExecutor = Executors.newFixedThreadPool(3);
ExecutorService writeExecutor = Executors.newFixedThreadPool(3);

下载池中的线程下载文件,然后将新线程提交到解析器线程池,文件名作为参数。这是在线程本身内完成的。然后,下载线程将从文件URL列表中下载另一个文件。

解析器线程完成从文件中解析出我想要的数据后,它会将包含数据的新线程提交给写入线程池,然后将其写入.csv文件。

我的问题是,如果有一个更优雅的解决方案。我没有真正做过复杂的线程。由于我有很多文件要下载和解析,我不希望任何线程在任何时候都处于空闲状态。再次提出的想法是,由于解析文件可能需要一段时间,因此我不妨制作单独的线程来专门下载这些文件。

3 个答案:

答案 0 :(得分:8)

为什么不只使用一个线程池。下载,解析和保存必须相互等待,所以最好的任务分离是每个文件使用一个线程。

答案 1 :(得分:2)

这并不是一个糟糕的做法,因为许多开发人员都在进行类似的编码。但是你需要记住一些事情。

第一,您不能仅仅因为您拥有更多线程而期望性能提升。根据CPU的数量,有最佳线程数。

第二,你必须确保如何处理异常。

第三,您必须确保在需要停止应用程序的事件中关闭所有线程池。

答案 2 :(得分:2)

所以你的问题有两个方面:

  1. 计算绑定
  2. IO bound
  3. 读取和写入文件是IO绑定的。 Async IO是IO绑定任务的最佳选择。 Java有AsynchronousFileChannel,允许您读取和写入文件,而不必担心通过完成处理程序实现延续的线程池。 Complete Example.

    AsynchronousFileChannel ch = AsynchronousFileChannel.open(path);
        final ByteBuffer buf = ByteBuffer.allocate(1024);
        ch.read(buf, 0, 0,
                new CompletionHandler() {
                    public void completed(Integer result, Integer length){        
                        ..
                    }
    
                    public void failed(Throwable exc, Integer length) {
                        ..
                    }
                }
        );
    

    你为写作做同样的事情,你只需要写入频道

    ch.write(...
    

    对于解析文件,这是一个计算绑定任务,并且你应该让你的CPU核心热,你可以分配一个等于你拥有的核心数的线程池。

     executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
    

    现在需要记住的是:您需要测试代码,并且测试并发代码很难。如果您无法证明其正确性,请不要这样做。