读取线程时的BufferedReader readline

时间:2012-10-10 11:32:47

标签: java multithreading concurrency readline

我不熟悉java中的并发编程。

我需要阅读,分析和处理速度极快的日志文件,所以我必须这样做 快速。 我的想法是读取文件(逐行)并匹配我想要的相关行 将这些行传递给可以在该行上进行进一步处理的单独线程。 我在以下示例代码中将这些线程称为“IOThread”。

我的问题是IOthread.run()中的BufferedReader readline显然永远不会返回。 什么是在线程内读取Stream的工作方式? 有没有比下面更好的方法?

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

class IOThread extends Thread {
    private InputStream is;
    private int t;

    public IOThread(InputStream is, int t)  {
        this.is = is;
        this.t = t;
        System.out.println("iothread<" + t + ">.init");
    }

    public void run() {
        try {
            System.out.println("iothread<" + t + ">.run");
            String line;

            BufferedReader streamReader = new BufferedReader(new InputStreamReader(is));
            while ((line = streamReader.readLine()) != null) {
                System.out.println("iothread<" + t + "> got line " + line);
            }
            System.out.println("iothread " + t + " end run");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Stm {
    public Stm(String filePath) {
        System.out.println("start");

        try {
            BufferedReader reader = new BufferedReader(new FileReader(filePath));

            PipedOutputStream po1 = new PipedOutputStream();
            PipedOutputStream po2 = new PipedOutputStream();
            PipedInputStream pi1 = new PipedInputStream(po1);
            PipedInputStream pi2 = new PipedInputStream(po2);
            IOThread it1 = new IOThread(pi1,1);
            IOThread it2 = new IOThread(pi2,2);

            it1.start();
            it2.start();
//          it1.join();
//          it2.join();

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("got line " + line);

                if (line.contains("aaa")) {
                    System.out.println("passing to thread 1: " + line);  
                    po1.write(line.getBytes());
                } else if (line.contains("bbb")) {
                    System.out.println("passing to thread 2: " + line);  
                    po2.write(line.getBytes());
                }
            }
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Stm(args[0]);
    }

}

示例输入文件是:

line 1
line 2
line 3 aaa ...
line 4
line 5 bbb ...
line 6 aaa ...
line 7
line 8 bbb ...
line 9 bbb ...
line 10

使用输入文件的文件名作为参数调用上面的代码。

2 个答案:

答案 0 :(得分:4)

您的iothread中的读者会因为以下原因而陷入您的while循环的第一次迭代的头部: 您从STM线程传递读取行的内容,但不附加换行符(\ n)。由于您的缓冲读取器等待新的行字符(如在.readLine()中),它将永远等待。您可以像这样修改代码:

   if (line.contains("aaa")) {
                System.out.println("passing to thread 1: " + line);  
                byte[] payload = (line+"\n").getBytes();
                po1.write(payload);
            } else if (line.contains("bbb")) {
                System.out.println("passing to thread 2: " + line);  
                byte[] payload = (line+"\n").getBytes();
                po2.write(payload);
            }

但我不得不说这根本不是一个优雅的解决方案,你可以使用阻塞队列或类似的东西为你的IOThreads提供内容。这样你就可以避免将输入到字符串转换为字节并返回到字符串(而不是说要删除所有的流)。

答案 1 :(得分:2)

恕我直言,你已经倒退了。创建多个线程以“处理”内容而不是从文件中读取数据。从文件中读取数据时,无论如何都是瓶颈,因此拥有多个线程不会有任何区别。最简单的解决方案是在给定线程中尽可能快地读取行,并将行存储在共享队列中。然后,可以通过任意数量的线程访问此队列以执行相关处理。

这样,当I / O或读取器线程忙于读取/等待数据时,您实际上可以执行并发处理。如果可能,请在阅读器线程中将“逻辑”保持在最小值。只需阅读这些行,让工作线程完成真正繁重的工作(匹配模式,进一步处理等)。只需使用线程安全队列,你应该是犹太教。

编辑:使用BlockingQueue的某些变体,基于数组或链接列表。