我正在编写一个包含3个线程的程序。一个人读取一个文本文件并将这些单词输入到一个大小为2的ArraylistBlockingQueue中。下一个单词取出该列表并反转其中的每个其他单词。最后一个线程接受单词并将它们写入新的文本文件。
除了我无法弄清楚如何中断和停止我的线程之外我一切正常。程序写入文本文件但永远不会结束。
主要方法
JFileChooser chooser = new JFileChooser();
File selectedFile = null;
File outFile = new File("output.txt");
int returnValue = chooser.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
selectedFile = chooser.getSelectedFile();
}
BlockingQueue text = new ArrayBlockingQueue(2);
BlockingQueue out = new ArrayBlockingQueue(2);
Thread input = new Thread(new inputClass(selectedFile, text));
Thread reverse = new Thread(new reverseClass(text, out));
Thread output = new Thread(new outputClass(out, outFile));
chooser.setSelectedFile(outFile);
if (chooser.showSaveDialog(chooser) == JFileChooser.APPROVE_OPTION) {
input.start();
reverse.start();
output.start();
}
输入
@Override
public void run() {
try {
Scanner s = new Scanner(f);
while (isRunning) {
try {
if(s.hasNext()){
text.put(s.next());
} else {
text.put(END);
}
} catch (InterruptedException ex) {
Logger.getLogger(inputClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (FileNotFoundException ex) {
Logger.getLogger(inputClass.class.getName()).log(Level.SEVERE, null, ex);
}
反向类 @覆盖 public void run(){
String original;
String temp = "";
String character = "";
int count = 1; // keeps track of whether or not a word should be reversed
while (isRunning) {
try {
original = text.take();
if(original.equalsIgnoreCase(END)){
Thread.currentThread().interrupt();
}
int length = original.length() - 1;
//if count is even then the word should be reversed.
if ((count % 2) == 0) {
// reverses the original string if a ? or . appears
if (original.contains("?") || original.contains(".")) {
character = original.charAt(length) + "";
for (int i = (length - 1); i >= 0; i--) {
temp = temp + original.charAt(i);
}
out.put(temp + character);
temp = "";
character = "";
// reverses the orgininal string if no ? or . appears
} else {
for (int i = length; i >= 0; i--) {
temp = temp + original.charAt(i);
}
out.put(temp);
temp = "";
}
count++;
} else {
out.put(original);
count++;
}
} catch (InterruptedException ex) {
Logger.getLogger(reverseClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
out.put(END);
} catch (InterruptedException ex) {
Logger.getLogger(reverseClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
输出代码 @覆盖 public void run(){
while (isRunning) {
String s = null;
try {
s = out.take();
} catch (InterruptedException ex) {
Logger.getLogger(outputClass.class.getName()).log(Level.SEVERE, null, ex);
}
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
try {
if (s.equalsIgnoreCase(END)) {
Thread.currentThread().interrupt();
}
writer.write(s + " ");
} finally {
writer.flush();
}
} catch (IOException ex) {
Logger.getLogger(outputClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
答案 0 :(得分:2)
来自Javadoc:
BlockingQueue
本质上不支持任何类型的"关闭"或"关闭"操作以指示不再添加任何项目。这些功能的需求和使用倾向于依赖于实现。例如,一种常见的策略是生产者插入特殊的流末端或毒物对象,这些对象在被消费者采用时会相应地进行解释。
我建议将值null
排队以指示流已结束;读者需要检查读取的值是null
,如果是,则终止。
答案 1 :(得分:0)
由于您一次只读一个单词,因此可以通过阻塞队列发送一个标志。发送字符串文字"此队列终止"就足够了。由于您一次只能读取一个单词,因此无法在您的单词反向程序中测试此字符串。
收到此消息后,您可以中断单词反向器。然后将相同的文字发送给作者。一旦作者收到旗帜,你也可以关闭作家。
A.K.A" Poison Pill"如Sotirios所述。
反转者类的例子:
/**
* Called when being executed. Reverses a word by taking from intake and
* places the reversed word into store
*/
@Override
public void run() {
boolean isInterrupted = false;
while (!isInterrupted) {
try {
StringBuilder str = new StringBuilder(intake.take());
//Exit condition
if (str.toString().equalsIgnoreCase(END_FLAG)) {
Thread.currentThread().interrupt();
}
//If it is a word to be reversed, then reverse it
if (oddWord % 2 == 1) {
str = reverseWord(str);
}
//Put word in queue and increment counter
store.put(str);
++oddWord;
} catch (InterruptedException ex) {
isInterrupted = true;
}
}
//Puts pill into queue when main body is done
try {
store.put(END_FLAG);
} catch (InterruptedException ex) {
System.err.printf("Error setting flag in store.%nWordReverser%n%s%n", ex);
}
}
来自Writer类的run()
方法:
/**
* Executes when being called in a thread
*/
@Override
public void run() {
boolean isInterrupted = false;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(output))) {
//Continue writing until the thread is interrupted
while (!isInterrupted) {
CharSequence word = in.take();
if (word.toString().equalsIgnoreCase(END_FLAG)) {
isInterrupted = true;
} else {
writer.write(word + " ");
}
}
} catch (InterruptedException | IOException ex) {
System.err.printf("Error writing to output file!%n%s%n", ex);
}
}
}
答案 2 :(得分:0)
你的代码已经到了一半...
对于在take()
方法中阻止的线程,您需要:
isRunning
标记设置为false
。Thread.interrupt()
。您可以通过在isRunning
的处理程序中将其设置为false
来避免公开InterruptedException
标记。
对于从Scanner
阅读时阻塞的帖子,Thread.interrupt()
应该会产生InterruptedIOException
。如果没有,那么在close()
正在使用的流上调用Scanner
就足够了。它需要一点点重组;即使用Scanner
或Reader
而不是InputStream
对象构建File
。