执行ExecutorService时出现NullPointerException

时间:2014-10-25 05:00:45

标签: java multithreading nullpointerexception runtime-error executorservice

我必须完成作为制作人/消费者计划的作业。我需要一个线程来读取一个文件,一个线程反转从第二个单词开始的每个其他单词,以及一个线程将单词写入文件。规则如下:

  1. 单词是任何字符序列,后跟空格。即使反转,标点符号也必须保留在单词的末尾
  2. 您的程序必须使用三个使用大小为2的阻塞队列进行通信的线程
  3. 除了队列之外,线程无法相互通信,也没有彼此的引用
  4. 必须从JFileChooser对象获取输入和输出文件。输入需要一次读取一个单词并通过阻塞队列将其传递给反转线程。处理线程需要从文件中获取每个其他单词并将其反转。所有线程都通过阻塞队列传递给输出。
  5. 输入线程完成阅读后需要关闭文件
  6. 输出需要在完成文字写入后关闭文件
  7. 当没有更多单词可以撤销时,反转单词的主题将终止
  8. 所有线程必须通过停止工作或中断来终止。不使用System.exit。
  9. 我已经完成了程序,但是我一直收到来自WordReverser类和WordWriter类的NullPointerException。


    我将在下面列出我的代码。

    它将遵循订单

    1. 主要课程
    2. WordReader:从文件中读取输入
    3. WordReverser:从第二个单词
    4. 开始,反转所有其他单词
    5. WordWriter:一次将一个单词写入输出文件
    6. 主类:

      package ProducerConsumerAssignment;
      
      import java.io.File;
      
      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.BlockingQueue;
      import java.util.concurrent.Executors;
      import java.util.concurrent.ExecutorService;
      
      import javax.swing.JFileChooser;
      
      /**
       * Test the producer consumer package
       *
       * @author Tyler Weaver
       */
      public class Tester {
      
          public static void main(String[] args) {
              final int MAX_SIZE = 2;
              File input, output;
              JFileChooser chooser = new JFileChooser();
              BlockingQueue fromReader = new ArrayBlockingQueue(MAX_SIZE);
              BlockingQueue toWriter = new ArrayBlockingQueue(MAX_SIZE);
              ExecutorService service = Executors.newCachedThreadPool();
              int returnVal, exitVal;
      
              do {
                  input = output = null;
                  returnVal = chooser.showOpenDialog(null);
                  if (returnVal == JFileChooser.APPROVE_OPTION) {
                      input = chooser.getSelectedFile();
                  }
              } while (returnVal != JFileChooser.APPROVE_OPTION);
      
              do {
                  exitVal = chooser.showSaveDialog(null);
                  if (exitVal == JFileChooser.APPROVE_OPTION) {
                      output = chooser.getSelectedFile();
                  }
              } while (exitVal != JFileChooser.APPROVE_OPTION);
      
              Runnable reader = new WordReader(input, fromReader);
              Runnable rev = new WordReverser(fromReader, toWriter);
              Runnable writer = new WordWriter(output, toWriter);
      
              service.execute(reader);
              service.execute(rev);
              service.execute(writer);
              service.shutdown();
          }
      }
      

      ReaderClass:

      package ProducerConsumerAssignment;
      
      import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader;
      
      import java.util.concurrent.BlockingQueue; import java.util.Scanner;
      
      /**  * Reads words from a file and places them into a blocking queue to be read  *  * @author Tyler Weaver  */ public class WordReader implements Runnable {
      
          //The blocking queue to store
          private static BlockingQueue<CharSequence> bin;
          private final File loc;             //File to read from
      
          /**
           * Constructor for WordReader
           *
           * @param input the text file to read from
           * @param bin the blocking queue to store the words
           */
          public WordReader(final File input, BlockingQueue bin) {
              loc = input;
              WordReader.bin = bin;
          }
      
          /**
           * Called when being executed Reads words from a file and places into a
           * blocking queue
           */
          @Override
          public void run() {
      
              try (Scanner in = new Scanner(new FileReader(loc))) {
                  while (in.hasNext()) {
                      bin.offer(in.next());
                  }
              } catch (FileNotFoundException ex) {
                  System.err.printf("Error finding File!%n%s%n", ex);
              }
          } }
      

      ReverserClass:

      package ProducerConsumerAssignment;
      
      import java.util.concurrent.BlockingQueue;
      
      /**
       * Takes a word from a blocking queue and reverses it. Puts the reversed word
       * into another blocking queue.
       *
       * @author Tyler Weaver
       */
      public class WordReverser implements Runnable {
      
          private static BlockingQueue<CharSequence> intake, store;
          private static int oddWord;
      
          /**
           * Constructor for Word Reverser
           *
           * @param intake the blocking queue to retrieve words from
           * @param store the blocking queue to store the words
           */
          public WordReverser(BlockingQueue intake, BlockingQueue store) {
              WordReverser.intake = intake;
              WordReverser.store = store;
              oddWord = 0;
          }
      
          /**
           * Called when being executed. Reverses a word by taking from intake and
           * places the reversed word into store
           */
          @Override
          public void run() {
              StringBuilder str = new StringBuilder(intake.poll());
              if (oddWord % 2 == 1) {
                  str = reverseWord(str);
              }
      
              store.offer(str);
              ++oddWord;
          }
      
          /**
           * Reverses a word, leaving behind punctuation if there is any
           *
           * @param word the word to reverse
           * @return a stringbuilder object containing the reversed word
           */
          private StringBuilder reverseWord(StringBuilder word) {
              char punct = Character.MAX_VALUE;
      
              //If has punctuation at the end, remove the punctuation
              if (!Character.isLetterOrDigit(word.charAt(word.length() - 1))) {
                  punct = word.charAt(word.length() - 1);
                  word.deleteCharAt(word.length() - 1);
              }
      
              word = word.reverse();
      
              if (punct == Character.MAX_VALUE) {
                  return word;
              }
      
              return word.append(punct);
          }
      }
      

      作家类:

      package ProducerConsumerAssignment;
      
      import java.io.BufferedWriter;
      import java.io.File;
      import java.io.FileWriter;
      import java.io.IOException;
      
      import java.util.concurrent.BlockingQueue;
      
      /**
       *
       * @author Tyler Weaver
       */
      public class WordWriter implements Runnable {
      
          private static BlockingQueue<CharSequence> in;
          private final File output;
      
          /**
           * Constructs a WordWriter object
           *
           * @param file the file to write words to
           * @param queue the blocking queue to retrieve words from
           */
          public WordWriter(final File file, BlockingQueue queue) {
              output = file;
              in = queue;
          }
      
          /**
           * Executes when being called in a thread
           */
          @Override
          public void run() {
              try (BufferedWriter out = new BufferedWriter(new FileWriter(output))) {
                  out.write(in.poll().toString() + " ");
              } catch (IOException ex) {
                  System.err.printf("Error closing the file!%n%s%n", ex);
              }
          }
      }
      

      我认为问题来自我的BlockingQueues,但我不确定。我们被教导如果BlockingQueue中没有任何单词,那么线程将阻塞并等待那里有一个单词。但似乎它根本不等待。任何帮助将不胜感激。

      编辑:抛出nullpointerexceptions的地方是WordReverser的第34行代码:StringBuilder str = new StringBuilder(intake.poll());

      和WordWriter类的第36行代码:

      out.write(in.poll().toString() + " ");
      

      这就是我感到困惑的原因。我们被告知,当尝试从不存在的BlockingQueue中提取数据时,线程会阻塞自己。

1 个答案:

答案 0 :(得分:2)

好吧,我看到至少有一个问题。您在.poll()上使用BlockingQueue,文档说明了这一点:

  

检索并删除此队列的头部,或返回{@code null}   如果此队列为空。

因此,如果您的队列中没有任何项目并且您从中进行了轮询并且还没有任何项目,那么您的代码将执行null项目的其余部分。

如果要在项目可用之前阻止,则应使用take()

  

检索并删除此队列的头部,必要时等待   直到一个元素可用。

这会导致线程像文档所说的那样等到项目可用。此操作还会抛出InterruptedException,因为调用线程可能会被中断。有办法阻止出版商/消费者在其他方面(例如毒丸),但我不打算在这里进入。

有不同的方法可以解决这个问题,但我认为您需要回答以下问题并查看您的设计:

  1. 您的WordReader何时完成发布数据?
  2. WordReverser如何知道数据不足?
  3. WordWriter如何知道没有更多数据要写?
  4. 您打算如何在线程之间提供数据?
  5. 您的ExecutorService启动器何时关闭?
  6. 您还应该看看您的静态班级成员并试着问问自己为什么要使用它们。