我必须完成作为制作人/消费者计划的作业。我需要一个线程来读取一个文件,一个线程反转从第二个单词开始的每个其他单词,以及一个线程将单词写入文件。规则如下:
我已经完成了程序,但是我一直收到来自WordReverser类和WordWriter类的NullPointerException。
我将在下面列出我的代码。
它将遵循订单
主类:
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中提取数据时,线程会阻塞自己。
答案 0 :(得分:2)
好吧,我看到至少有一个问题。您在.poll()
上使用BlockingQueue
,文档说明了这一点:
检索并删除此队列的头部,或返回{@code null} 如果此队列为空。
因此,如果您的队列中没有任何项目并且您从中进行了轮询并且还没有任何项目,那么您的代码将执行null
项目的其余部分。
如果要在项目可用之前阻止,则应使用take()
:
检索并删除此队列的头部,必要时等待 直到一个元素可用。
这会导致线程像文档所说的那样等到项目可用。此操作还会抛出InterruptedException
,因为调用线程可能会被中断。有办法阻止出版商/消费者在其他方面(例如毒丸),但我不打算在这里进入。
有不同的方法可以解决这个问题,但我认为您需要回答以下问题并查看您的设计:
WordReader
何时完成发布数据?WordReverser
如何知道数据不足?WordWriter
如何知道没有更多数据要写?ExecutorService
启动器何时关闭?您还应该看看您的静态班级成员并试着问问自己为什么要使用它们。