中断线程中的BlockingQueue

时间:2014-10-26 01:05:00

标签: java multithreading interrupt

我正在编写一个包含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);

        }
    }

3 个答案:

答案 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()方法中阻止的线程,您需要:

  1. isRunning标记设置为false
  2. 在线程对象上调用Thread.interrupt()
  3. 您可以通过在isRunning的处理程序中将其设置为false来避免公开InterruptedException标记。

    对于从Scanner阅读时阻塞的帖子,Thread.interrupt()应该会产生InterruptedIOException。如果没有,那么在close()正在使用的流上调用Scanner就足够了。它需要一点点重组;即使用ScannerReader而不是InputStream对象构建File