首页 > 解决方案 > 如何使用多线程将多个txt文件读入一个列表?

问题描述

我正在学习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() 来等待三个线程的完成,但我的代码无法正常工作。

标签: javamultithreading

解决方案


基于您的代码的一种简单方法是添加一个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);

推荐阅读