【问题标题】:How to read multiple txt files into one List with multithread?如何使用多线程将多个txt文件读入一个列表?
【发布时间】:2021-02-17 07:13:58
【问题描述】:

我正在学习 Java 中的多线程。为了练习,我想做多线程并行读取三个txt文件,将三个文件的每一行添加到一个List中。这是我的代码:

ArrayList<String> allLinesFromFiles= new ArrayList<String>();
Lock blockThread=new ReentrantLock();
Thread t = null;
    for (String file : files) {
        
        t= new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    FileReader fichero;
                    fichero = new FileReader(file);
                    BufferedReader bufferFichero = new BufferedReader(fichero);
                    String line = bufferFichero.readLine();
                    
                    while (line != null) {
                        writeList(line.toLowerCase());
                        line = bufferFichero.readLine();
                    }
            
                    bufferFichero.close();
                    
                }catch (IOException e) {
                    System.out.println("Error IO");
                }
            }
            
            private void writeList(String line) {
                blockThread.lock();
                allLinesFromFiles.add(line);
                blockThread.unlock();
            }
        });
        t.start();  
    }
    try {
        t.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Collections.sort(allLinesFromFiles);

我在方法“writeList”中使用了锁定/解锁(ReentrantLock)来同步,因为我认为可能需要三个线程写入 ArrayList。是正确的?我是否应该使用 CopyOnWriteArrayList 而不是 ArrayList?

我使用 join() 来等待三个线程的完成,但我的代码不能正常工作。

【问题讨论】:

  • 您只在一个线程(最后一个文件的线程)上调用join(),因此当您对列表进行排序时,并非所有线程都已完成。
  • 您只有一个关键问题 - 正如 Kayaman 所说,您只为最后一个线程调用 join()。在准备时将所有线程存储在一个数组/列表中,然后在循环/for each 中调用 .join() foe 每个线程。不要使用下面建议的 AtomicCounters 和 sleeps。旧好的 .join() 非常适合您的情况。第二个小问题是您应该在 finally 块中关闭 FileReader 或使用 try-with-resource。

标签: java multithreading


【解决方案1】:

基于您的代码的一个简单方法是添加一个AtomicInteger 计数以知道读取线程是否结束,并且主线程等待结束:

List<String> files = Arrays.asList("a.txt", "b.txt", "c.txt");
                ArrayList<String> allLinesFromFiles= new ArrayList<String>();
                Lock blockThread=new ReentrantLock();
                AtomicInteger count = new AtomicInteger(0); // counter
                Thread t = null;
                for (String file : files) {
                        t= new Thread(new Runnable() {
                                @Override
                                public void run() {
                                        try {
                                                FileReader fichero;
                                                fichero = new FileReader(getClass().getClassLoader().getResource(file).getFile());
                                                BufferedReader bufferFichero = new BufferedReader(fichero);
                                                String line = bufferFichero.readLine();

                                                while (line != null) {
                                                        writeList(line.toLowerCase());
                                                        line = bufferFichero.readLine();
                                                }

                                                bufferFichero.close();
                                        }catch (IOException e) {
                                                e.printStackTrace();
                                                System.out.println("Error IO");
                                        }finally {
                                                count.getAndIncrement(); // counter ++
                                        }
                                }

                                private void writeList(String line) {
                                        blockThread.lock();
                                        allLinesFromFiles.add(line);
                                        blockThread.unlock();
                                }
                        });
                        t.start();
                }
                while (count.intValue() < 3) {
                        TimeUnit.MILLISECONDS.sleep(500);
                }
                Collections.sort(allLinesFromFiles);
                System.out.println(allLinesFromFiles);

但是,更好的方法是:

List<String> filePaths = Arrays.asList("a.txt", "b.txt", "c.txt");
                List<String> result = new ArrayList<>();
                filePaths.parallelStream().forEach(filePath -> {
                        try {
                                List<String> strings = Files.readAllLines(
                                        Paths.get(ReadTest.class.getClassLoader().getResource(filePath).toURI()));
                                result.addAll(strings);
                        } catch (IOException | URISyntaxException e) {
                                e.printStackTrace();
                        }
                });
                Collections.sort(result);
                System.out.println(result);

【讨论】:

  • 你同时写入普通的非线程安全 List result = new ArrayList()?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多