Java:InputStream上的并发读取

Java:InputStream上的并发读取,java,performance,concurrency,inputstream,Java,Performance,Concurrency,Inputstream,我已经四处寻找了一段时间,我对这个问题有点困惑。我希望能够获取一个输入流并以段的形式并发地读取它。这些段不会相互交互,它们只是从上载的文件插入或更新到数据库中的值。通过设置段大小,然后在旋转新线程以处理转换和插入/更新之前向前跳过,是否可以同时读取输入流 从本质上讲,该文件是一个ID列表(每行一个ID),不过如果我可以指定一个分隔符则更好。有些文件可能很大,因此我希望将数据处理并转换为段,以便在插入/更新数据库后,可以释放JVM内存。这可能吗?如果是这样的话,有没有图书馆已经这样做了 干杯并提前

我已经四处寻找了一段时间,我对这个问题有点困惑。我希望能够获取一个输入流并以段的形式并发地读取它。这些段不会相互交互,它们只是从上载的文件插入或更新到数据库中的值。通过设置段大小,然后在旋转新线程以处理转换和插入/更新之前向前跳过,是否可以同时读取输入流

从本质上讲,该文件是一个ID列表(每行一个ID),不过如果我可以指定一个分隔符则更好。有些文件可能很大,因此我希望将数据处理并转换为段,以便在插入/更新数据库后,可以释放JVM内存。这可能吗?如果是这样的话,有没有图书馆已经这样做了

干杯并提前表示感谢


阿列克谢蓝

一个好的方法可能是使用一个读卡器读取块,然后将每个块从线程池中交给工作线程。考虑到这些将被插入到数据库中,与读取输入相比,插入将是非常慢的部分,因此单个线程应该足以读取

下面是一个示例,它将
System.in
中的每一行的处理交给工作线程。如果在单个事务中执行大量插入,则数据库插入的性能会更好,因此传入一组(比如1000行)比传入一行(如示例所示)要好

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static class Worker implements Runnable {
        private final String line;

        public Worker(String line) {
            this.line = line;
        }

        @Override
        public void run() {
            // Process line here.
            System.out.println("Processing line: " + line);
        }
    }

    public static void main(String[] args) throws IOException {
        // Create worker thread pool.
        ExecutorService service = Executors.newFixedThreadPool(4);

        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
        String line;

        // Read each line and hand it off to a worker thread for processing.
        while ((line = buffer.readLine()) != null) {
            service.execute(new Worker(line));
        }
    }
}

我认为您不能同时读取输入流。这就是契约定义读取、重置和标记的原因——其思想是流在内部跟踪已读取和未读取的内容


如果您正在读取一个文件,只需打开多个流即可。您可以使用该方法将其他线程的标记向前移动,以避免重复行处理。可能也有帮助,因为它提供读取功能。

首先,要从不同的偏移量同时读取文件,您需要随机访问文件,这意味着从任何位置读取文件。Java允许在Java.in中使用RandomAccessFile或在Java.nio中使用SeekableByteChannel:

我认为出于速度原因,您会更喜欢java.nio。

现在您知道如何从任何位置读取,但您需要同时执行此操作。对于同一个文件访问对象,这是不可能的,因为它们保留文件中的位置。因此,您需要与线程一样多的文件访问对象。既然你是在读而不是在写,那应该没问题

现在您知道了如何从多个不同的偏移量同时读取同一个文件


但是想想你的表现。尽管有多个线程,但您只有一个磁盘驱动器和随机读取(多个线程访问同一个文件),性能要比顺序读取(一个线程读取一个文件)慢得多。即使是raid 0或1-也无所谓。顺序阅读总是快得多。因此,在您的情况下,我建议您在一个线程中读取文件,并向其他线程提供该读取线程中的数据。

是的,缓冲读取器+跳过是我目前的做法,需要更多的工作,但我确信使用单次顺序读取并将工作移动到其他线程将是一个很好的改进。为链接干杯。您好,谢谢您的示例^。^因此,如果我将1000行读取到StringBuffer中,然后将其传递给工作线程进行处理并插入/更新到数据库中,您认为这是一种好方法吗?:)最好将1000行读入
列表
字符串[]
。如果您将它们读入
StringBuffer
中,那么它将是一个字符串,您需要再次解析出单独的行。