Java 在不同线程中处理文件写入的正确方法

Java 在不同线程中处理文件写入的正确方法,java,multithreading,thread-safety,threadpool,executorservice,Java,Multithreading,Thread Safety,Threadpool,Executorservice,我正在寻找写入文件多次(100k+)和写入将发生在一个脆弱的网络。为此,我正在考虑使用JavaExecutorService来帮助生成线程,但我不确定哪种设置组合能够正确地实现以下操作: 一次只允许进行一次写入(当然是订购事宜) 允许写操作有足够的时间进行每次写操作(比如说5秒),此时只需 如果写入速度慢,请让执行器在队列中收集写入并等待 在线程队列为空之前,不要允许整个程序退出 用编剧把线分开。也就是说,如果同一个writer出现在这个函数中,那么将它放在它自己的队列中。如果输入了不同的wri

我正在寻找写入文件多次(100k+)和写入将发生在一个脆弱的网络。为此,我正在考虑使用Java
ExecutorService
来帮助生成线程,但我不确定哪种设置组合能够正确地实现以下操作:

  • 一次只允许进行一次写入(当然是订购事宜)
  • 允许写操作有足够的时间进行每次写操作(比如说5秒),此时只需
  • 如果写入速度慢,请让执行器在队列中收集写入并等待
  • 在线程队列为空之前,不要允许整个程序退出
  • 用编剧把线分开。也就是说,如果同一个writer出现在这个函数中,那么将它放在它自己的队列中。如果输入了不同的writer指针,则为其指定自己的队列(无需在同一队列中放置不同的writer)
  • 我相信这可以通过结合执行器功能以及主程序对象上的
    .wait()
    .notify()
    命令来实现。然而,我只是不确定如何精确地使用executor API来完成这项工作

    以下是我得到的:

    private void writeToFileInSeperateThread(final PrintWriter writer, final String text) {
      ExecutorService executor = Executors.newSingleThreadExecutor();
      try {
        executor.submit(new Thread(new Runnable() {
          public void run() {
            writer.println(text);
          }
        })).get(5L, TimeUnit.SECONDS);
      } catch (Exception e) {
        e.printStackTrace();
      }
      executor.shutdown();
    }
    
    在单个进程中,该方法将被调用100k多次,因此我不确定每次是创建一个新的
    ExcutorService
    实例,还是使用相同的实例?(在我尝试使用同一个线程时,我不断得到一些异常,我认为这些异常与
    .newSingleThreadExecutor()
    指令有关

    希望保持Java 5兼容,但Java 6可以。在Windows XP/7上运行

    更新: 这似乎在初始测试中起到了作用:

      private class WriterStringPair {
        public final PrintWriter writer;
        public final String text;
    
        public WriterStringPair(PrintWriter writer, String text) {
          this.writer = writer;
          this.text = text;
        }
      }
    
      private void writeTextInSeperateThread(Writer writer, String text) {
        try {
          textQueue.offer(new WriterStringPair(writer, text), 300L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
          errOut.println(e);
          e.printStackTrace();
        }
      }
    
      final BlockingQueue<WriterStringPair> textQueue = new ArrayBlockingQueue<WriterStringPair>(500);
    
      private void setWritingThread() {
        new Thread((new Runnable() {
          public void run() {
            WriterStringPair q;
            while (!shutdown && !Thread.currentThread().isInterrupted()) {
              try {
                q = textQueue.poll(1L, TimeUnit.SECONDS);
                if (q != null) {
                  q.writer.write(q.text + "\n");
                  q.writer.flush();
                }
              } catch (Exception e) {
                e.printStackTrace();
              }
            }
          }
        })).start();
      }
    
    私有类WriterStringPair{
    公共最终印刷作者;
    公共最终字符串文本;
    公共WriterStringPair(PrintWriter编写器,字符串文本){
    this.writer=writer;
    this.text=文本;
    }
    }
    私有void WriteTextInsperateThread(编写器编写器,字符串文本){
    试一试{
    textQueue.offer(新的WriterStringPair(writer,text),300L,时间单位为秒);
    }捕捉(中断异常e){
    打印错误(e);
    e、 printStackTrace();
    }
    }
    最终阻塞队列textQueue=新的ArrayBlockingQueue(500);
    私有void setWritingThread(){
    新线程((新可运行的(){
    公开募捐{
    WriterStringPair q;
    而(!shutdown&!Thread.currentThread().isInterrupted()){
    试一试{
    q=textQueue.poll(1L,时间单位:秒);
    如果(q!=null){
    q、 writer.write(q.text+“\n”);
    q、 writer.flush();
    }
    }捕获(例外e){
    e、 printStackTrace();
    }
    }
    }
    })).start();
    }
    
    如果不了解更多关于您在“脆弱”网络上编写文件的详细信息及其含义,我们很难给出具体信息。但下面是一些需要思考的问题

    我会计算出多少并发写入程序在这里为您提供了最好的性能,或者在目标上提供了最可靠的输出。然后,您应该启动固定数量的这些写入程序,每个写入程序都从共享的
    BlockingQueue
    (或者每个写入程序一个队列,如果有必要的话)。您应该很快超过IO或网络带宽,因此从5个左右的写入程序开始,并根据需要进行上下操作

    public void run() {
       writer.println(text);
    }
    
    是的,你不想在每行一个作业的情况下做这种事情。最好将
    字符串文本
    放入
    阻塞队列
    ,然后让你的writer
    Runnable
    类在
    ExecutorService
    中运行,并从该队列中退出队列,并且仅在队列为空或
    sh时停止utdown
    boolean已设置

    正如Peter提到的,在使用排队的文本字符串填充内存时需要小心。如果输入的文本较大,则应将
    BlockingQueue
    的限制设置为几百左右

    我不确定每次是创建一个新的
    ExecutorService
    实例,还是使用同一个实例

    当然,您应该有一个单一的服务,而不是一次又一次地创建一个

    我相信这可以通过executor特性的组合以及主程序对象上的.wait()和.notify()命令来实现

    如果写得正确,您不需要使用“等待并通知”。我会有一个
    volatile boolean shutdown=false
    ,您的所有编写者都会看到它。他们每个人都会通过查看关闭来从文本队列中退出。类似于:

    while (!shutdown && !Thread.currentThread().isInterrupgted()) {
        String text = textQueue.poll(1, TimeUnit.SECONDS);
        if (text != null) {
            // write the text
        }
    }
    

    如果写入失败或其他情况,您可以重试或做任何必要的操作。

    在不了解有关您通过“脆弱”网络写入文件的详细信息以及方法的情况下,我们很难给出具体信息。但这里有一些事情需要考虑

    我会计算出多少并发写入程序在这里为您提供了最好的性能,或者在目标上提供了最可靠的输出。然后,您应该启动固定数量的这些写入程序,每个写入程序都从共享的
    BlockingQueue
    (或者每个写入程序一个队列,如果有必要的话)。您应该很快超过IO或网络带宽,因此从5个左右的写入程序开始,并根据需要进行上下操作

    public void run() {
       writer.println(text);
    }
    
    是的,你不想在每行一个作业的情况下做这种事情。最好将
    字符串文本
    放入
    阻塞队列
    ,然后让你的writer
    Runnable
    类在
    ExecutorService
    中运行,并从该队列中退出队列,并且仅在队列为空或
    sh时停止utdown
    boolean已设置

    正如Peter提到的,在使用排队的文本字符串填充内存时需要小心。如果输入的文本较大,则应将
    BlockingQueue
    的限制设置为几百左右

    我不确定我是否应该成为crea