Java 当其他任务完成时,强制BufferedWriter从BlockingQueue写入

Java 当其他任务完成时,强制BufferedWriter从BlockingQueue写入,java,multithreading,concurrency,threadpool,Java,Multithreading,Concurrency,Threadpool,我正在用JSoup编写简单的html解析器。我有大约50000个链接要检查,所以我认为这是学习线程和concurnecy的好机会。我已经向ExecutorService注册了8个任务:其中6个任务解析ArrayList中存储的一些数据的链接,然后将其添加到BlockingQueues中。其中两个任务是基于BufferedWriter的文件编写器。问题是当我的6个任务完成所有链接时,文件编写器停止从BlockingQueue写入数据,因此我丢失了部分数据。我是java的新手,所以如果你能帮我一下。

我正在用JSoup编写简单的html解析器。我有大约50000个链接要检查,所以我认为这是学习线程和concurnecy的好机会。我已经向ExecutorService注册了8个任务:其中6个任务解析ArrayList中存储的一些数据的链接,然后将其添加到BlockingQueues中。其中两个任务是基于BufferedWriter的文件编写器。问题是当我的6个任务完成所有链接时,文件编写器停止从BlockingQueue写入数据,因此我丢失了部分数据。我是java的新手,所以如果你能帮我一下。。。。守则:

主文件:

public static void main(String[] args) {
    BlockingQueue<ArrayList<String>> units = new ArrayBlockingQueue<ArrayList<String>>(50, true);
    BlockingQueue<ArrayList<String>> subjects = new ArrayBlockingQueue<ArrayList<String>>(50, true);
    File subjectFile = new File("lekarze.csv");
    File unitFile = new File("miejsca.csv");
    ExecutorService executor = Executors.newFixedThreadPool(9);
    executor.submit(new Thread(new FileSaver(subjects, subjectFile)));
    executor.submit(new Thread(new FileSaver(units, unitFile)));
    for(int i = 29323; i < 29400; i++){
        executor.submit(new ParserDocsThread(i, subjects, units, errors));
    }

    executor.shutdown();
}
publicstaticvoidmain(字符串[]args){
BlockingQueue单位=新的ArrayBlockingQueue(50,真);
BlockingQueue subjects=新的ArrayBlockingQueue(50,true);
File subjectFile=新文件(“lekarze.csv”);
File unitFile=新文件(“miejsca.csv”);
ExecutorService executor=Executors.newFixedThreadPool(9);
submit(新线程(新文件保存器(subjects,subjectFile));
提交(新线程(新文件保存器(单位,单位文件));
对于(int i=29323;i<29400;i++){
submit(新的ParserDocsThread(i,主题,单位,错误));
}
executor.shutdown();
}
FileSaver类:

package parser;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;

public class FileSaver implements Runnable {
    private BlockingQueue<ArrayList<String>> toWrite = null;
    private File outputFile = null;
    private BufferedWriter writer = null;

    public FileSaver(BlockingQueue<ArrayList<String>> queue, File file){
       toWrite = queue;
       outputFile = file;
   }

    public void run() {
       try {
          writer = new BufferedWriter(new FileWriter(outputFile, true));
          while(true){
              try{
                  save(toWrite.take());
              } catch(InterruptedException e) {
                  e.printStackTrace();
              }
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
  }

  private void save(ArrayList<String> data){
      String temp ="";
      int size = data.size();
      for(int i = 0; i < size; i++){
          temp += data.get(i);
          if(i != size - 1) temp += '\t'; 
      }
      try {
          writer.write(temp);
          writer.newLine();
      } catch (IOException e) {
          e.printStackTrace();
      }
  }
}
包解析器;
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileWriter;
导入java.io.IOException;
导入java.util.ArrayList;
导入java.util.concurrent.BlockingQueue;
公共类FileSaver实现可运行{
private BlockingQueue toWrite=null;
私有文件outputFile=null;
private BufferedWriter=null;
公共文件保存器(阻止队列、文件文件){
toWrite=队列;
outputFile=文件;
}
公开募捐{
试一试{
writer=newbufferedwriter(newfilewriter(outputFile,true));
while(true){
试一试{
保存(toWrite.take());
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
私有void保存(ArrayList数据){
字符串temp=“”;
int size=data.size();
对于(int i=0;i

在ParserDocsThread中,我只使用put()方法将元素添加到BlockingQueue。

您的使用者线程没有干净地结束,因为
take()
调用正在等待新数组,并且没有关闭缓冲写入程序。ServiceExecutor放弃等待这些线程完成,并杀死它们。这导致写入程序中的最后几行无法写入磁盘

您应该使用
轮询(10,TimeUnit.SECONDS)
(但要有适当的超时)。超时后,消费者将放弃生产者,您应该确保正确关闭缓冲写入程序,以便正确打印最后一个缓冲区

try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, true)))
{
    while(true){
        List<String> data = toWrite.poll(10, TimeUnit.SECONDS);
        if (data == null) {
           break;
        }
        save(data, writer);
    }
} catch (...) {
}

您可能还希望在executor servier(如:)上调用
waitTermination
,等待时间大于轮询超时。

您的使用者线程不会干净结束,因为
take()
调用正在等待新数组,并且没有关闭缓冲写入程序。ServiceExecutor放弃等待这些线程完成,并杀死它们。这导致写入程序中的最后几行无法写入磁盘

您应该使用
轮询(10,TimeUnit.SECONDS)
(但要有适当的超时)。超时后,消费者将放弃生产者,您应该确保正确关闭缓冲写入程序,以便正确打印最后一个缓冲区

try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, true)))
{
    while(true){
        List<String> data = toWrite.poll(10, TimeUnit.SECONDS);
        if (data == null) {
           break;
        }
        save(data, writer);
    }
} catch (...) {
}
您可能还希望在executor servier(如:)上调用
waitTermination
,等待时间大于轮询超时。

executor.submit(新线程(新文件保存器(…))-不要向执行器提交线程。
Thread
实现
Runnable
这一事实具有误导性,可以说是一个历史错误。只需提交作业:
executor.submit(新文件保存程序(…)执行器.submit(新线程(新文件保存器(…))-不要向执行器提交线程。
Thread
实现
Runnable
这一事实具有误导性,可以说是一个历史错误。只需提交作业:
executor.submit(新文件保存程序(…)