Java 永无止境的线

Java 永无止境的线,java,multithreading,io,blockingqueue,Java,Multithreading,Io,Blockingqueue,这是我的密码: public class BigFileReader implements Runnable { private final String fileName; int a = 0; private final BlockingQueue<String> linesRead; public BigFileReader(String fileName, BlockingQueue<String> linesRead) {

这是我的密码:

   public class BigFileReader implements Runnable {
    private final String fileName;
    int a = 0;

    private final BlockingQueue<String> linesRead;
    public BigFileReader(String fileName, BlockingQueue<String> linesRead) {
        this.fileName = fileName;
        this.linesRead = linesRead;
    }
    @Override
    public void run() {
        try {
            //since it is a sample, I avoid the manage of how many lines you have read
            //and that stuff, but it should not be complicated to accomplish
            BufferedReader br = new BufferedReader(new FileReader(new File("E:/Amazon HashFile/Hash.txt")));
            String str = "";

            while((str=br.readLine())!=null)
            {
                linesRead.put(str);
                System.out.println(a);
                a++;
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        System.out.println("Completed");
    }
}





public class BigFileProcessor implements Runnable {
    private final BlockingQueue<String> linesToProcess;
    public BigFileProcessor (BlockingQueue<String> linesToProcess) {
        this.linesToProcess = linesToProcess;
    }
    @Override
    public void run() {
        String line = "";
        try {
            while ( (line = linesToProcess.take()) != null) {
                //do what you want/need to process this line...
                String [] pieces = line.split("(...)/g");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}





public class BigFileWholeProcessor {
    private static final int NUMBER_OF_THREADS = 2;
    public void processFile(String fileName) {

        BlockingQueue<String> fileContent = new LinkedBlockingQueue<String>();
        BigFileReader bigFileReader = new BigFileReader(fileName, fileContent);
        BigFileProcessor bigFileProcessor = new BigFileProcessor(fileContent);
        ExecutorService es = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
        es.execute(bigFileReader);
        es.execute(bigFileProcessor);
        es.shutdown();

    }
}
公共类BigFileReader实现可运行{
私有最终字符串文件名;
int a=0;
专用最终阻塞队列行读取;
公共BigFileReader(字符串文件名,阻止队列行读取){
this.fileName=文件名;
this.linesRead=linesRead;
}
@凌驾
公开募捐{
试一试{
//由于这是一个示例,我避免了管理您阅读了多少行
//这些东西,但完成起来并不复杂
BufferedReader br=新的BufferedReader(新文件阅读器(新文件(“E:/Amazon HashFile/Hash.txt”));
字符串str=“”;
而((str=br.readLine())!=null)
{
线头放置(str);
系统输出打印项次(a);
a++;
}
}捕获(例外情况除外){
例如printStackTrace();
}
系统输出打印项次(“完成”);
}
}
公共类BigFileProcessor实现可运行{
私有最终阻塞队列linesToProcess;
公共BigFileProcessor(BlockingQueue linesToProcess){
this.linesToProcess=linesToProcess;
}
@凌驾
公开募捐{
字符串行=”;
试一试{
而((line=linesToProcess.take())!=null){
//执行您想要/需要的操作来处理此生产线。。。
String[]parties=line.split(“(…)/g”);
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公共类BigFileWholeProcessor{
私有静态最终整数线程数=2;
公共void进程文件(字符串文件名){
BlockingQueue fileContent=新建LinkedBlockingQueue();
BigFileReader BigFileReader=新的BigFileReader(文件名、文件内容);
BigFileProcessor BigFileProcessor=新的BigFileProcessor(fileContent);
ExecutorService es=Executors.newFixedThreadPool(线程数);
执行(bigFileReader);
执行(bigFileProcessor);
es.shutdown();
}
}
这段代码很好,但有一个大问题。也就是说,这条线永远不会结束!即使整个过程都完成了,我仍然可以确定程序是否还活着。这里出了什么问题?

将一直阻止,直到元素可用:

检索并删除此队列的头,如有必要,等待元素可用

因此,在BigFileReader读取完输入文件并将行放入BlockingQueue之后,BigFileProcessor将在
take()
方法中永远等待新的输入

您可能希望找到一种方法来向BigFileProcessor发出信号,表示将不再有任何输入放在BlockingQueue上,可以通过添加到队列或找到其他方法来告诉BigFileProcessor停止调用
take()

哨兵方法的一个例子:

public class BigFileReader implements Runnable {
    public static final String SENTINEL = "SENTINEL"; //the actual value isn't very important
    ...

    while((str=br.readLine())!=null) {
        linesRead.put(str);
    }
    //when reading the file is done, add SENTINEL to the queue
    linesRead.put(SENTINEL);
}

//inside BigFileProcessor...
while ( (line = linesToProcess.take()) != null) {
    // check if value in queue is sentinel value
    if (line == BigFileReader.SENTINEL) {
         //break out of the while loop
         break;
    }
    //otherwise process the line as normal
}
另一种方法是使用而不是
take()
,逻辑是,如果BigFileProcessor无法从队列中读取任何内容超过N秒,则会中断其循环,等等。

将阻塞,直到元素可用:

检索并删除此队列的头,如有必要,等待元素可用

因此,在BigFileReader读取完输入文件并将行放入BlockingQueue之后,BigFileProcessor将在
take()
方法中永远等待新的输入

您可能希望找到一种方法来向BigFileProcessor发出信号,表示将不再有任何输入放在BlockingQueue上,可以通过添加到队列或找到其他方法来告诉BigFileProcessor停止调用
take()

哨兵方法的一个例子:

public class BigFileReader implements Runnable {
    public static final String SENTINEL = "SENTINEL"; //the actual value isn't very important
    ...

    while((str=br.readLine())!=null) {
        linesRead.put(str);
    }
    //when reading the file is done, add SENTINEL to the queue
    linesRead.put(SENTINEL);
}

//inside BigFileProcessor...
while ( (line = linesToProcess.take()) != null) {
    // check if value in queue is sentinel value
    if (line == BigFileReader.SENTINEL) {
         //break out of the while loop
         break;
    }
    //otherwise process the line as normal
}

另一种方法是使用而不是
take()
,逻辑是,如果BigFileProcessor在N秒以上无法从队列中读取任何内容,则会中断其循环,等等。

BlockingQueue,顾名思义,就是阻塞。也就是说,一旦执行queue.take(),线程就会挂起,直到队列中有东西要执行为止。为了终止线程,您需要使用queue.isEmpty()来知道队列中是否还有消息。我建议在读完文件后发送一条文件结束消息,以便知道何时退出循环。

BlockingQueue顾名思义就是阻塞。也就是说,一旦执行queue.take(),线程就会挂起,直到队列中有东西要执行为止。为了终止线程,您需要使用queue.isEmpty()来知道队列中是否还有消息。我建议您在读完文件后发送一条文件结束消息,以便知道何时退出循环。

您有什么证据表明它永远不会结束?如何提交
Runnable
?在开始之前,请先设置deamon(true)。与实际问题无关,但
a++
可能不是线程安全的。您应该改用
AtomicInteger
。@yshave这里的
a++
没有问题,因为只有一个线程在读/写它的值。@mattb True,但是
a
是一个字段,而不是局部变量,这一事实表明其他人将在某个时候读取它。缺少其他一些同步(
a
是易失性的,a
Thread.join
等),读取将不是线程安全的。最简单的方法可能是使其
易失性
(而不是像我最初写的那样
原子整数
)。当然,这是假设这个可运行实例没有在两个线程上运行——如果是,那么即使是
volatile
也不够。你有什么证据表明它永远不会结束?如何提交
Runnable
?在开始之前,请先设置deamon(true)。与实际问题无关,但
a++
可能不是线程安全的。您应该使用原子整数