简体   繁体   English

为什么我的ArrayBlockingQueue在列入列表后导致空队列?

[英]Why does my ArrayBlockingQueue result in an empty queue after putting a list in it?

This is the first time I have asked a question on StackOverflow. 这是我第一次在StackOverflow上提出问题。 The problem I have is the following: 我遇到的问题如下:

I have a Producer and Consumer class. 我有一个制作人和消费者类。 In the Producer class I read a file line by line and put these lines of text in a List of Strings. 在Producer类中,我逐行读取文件,并将这些文本行放在字符串列表中。 When the list has an x amount of lines. 当列表具有x行数时。 This list gets added to an ArrayBlockingQueue. 此列表将添加到ArrayBlockingQueue。 I have one Producer Thread that is started within the main thread. 我有一个在主线程中启动的生产者线程。 Besides this I start a couple of Consumer threads. 除此之外,我开始使用几个Consumer线程。 The Consumer thread takes an item from the queue, which should be a list, and walks through this list of lines looking for a particular word. Consumer线程从队列中获取一个项目,该项目应该是一个列表,并遍历此行列表以查找特定单词。 When the word is found it increments a count variable. 当找到该单词时,它会递增计数变量。

What happends is that when the Consumer takes an item from the queue, it says that it is empty. 发生的事情是当Consumer从队列中获取一个项目时,它表示它是空的。 I cannot figure out why because my producer should certainly add it to the queue. 我无法弄清楚为什么,因为我的制作人当然应该将它添加到队列中。

My code looks like this: 我的代码看起来像这样:

Consumer class: 消费者阶层:

public static class Consumer implements Callable<Integer> {

    int count = 0;

    @Override
    public Integer call() throws Exception {
        List<String> list = new ArrayList<>();
        list = arrayBlockingQueueInput.take();
        do {
            if (!list.isEmpty()){
                for (int i = 0; i < arrayBlockingQueueInput.take().size(); i++) {
                    for (String element : list.get(i).split(" ")) {
                        if (element.equalsIgnoreCase(findWord)) {
                            count++;
                        }
                    }
                }
            } else {
                arrayBlockingQueueInput.put(list);
            }
        } while (list.get(0) != "HALT");
        return count;
    }
}

Producer Class: 制片人类:

public static class Producer implements Runnable {

    @Override
    public void run() {
        try {
            FileReader file = new FileReader("src/testText.txt");
            BufferedReader br = new BufferedReader(file);

            while ((textLine = br.readLine()) != null) {

                if (textLine.isEmpty()) {
                    continue;
                }

                /* Remove punctuation from the text, except of punctuation that is useful for certain words.
                * Examples of these words are don't or re-enter */
                textLine = textLine.replaceAll("[[\\W]&&[^']&&[^-]]", " ");

                /* Replace all double whitespaces with single whitespaces.
                * We will split the text on these whitespaces later */
                textLine = textLine.replaceAll("\\s\\s+", " ");

                textLine = textLine.replaceAll("\\n", "").replaceAll("\\r", "");

                if (results.isEmpty()) {
                    results.add(textLine);
                    continue;
                }
                if (results.size() <= SIZE) {
                    results.add(textLine);
                    if (results.size() == SIZE) {
                        if (arrayBlockingQueueInput.size() == 14){
                            List<String> list = new ArrayList<String>();
                            list.add(HALT);
                            arrayBlockingQueueInput.put(list);
                        } else{
                            arrayBlockingQueueInput.put(results);
                            results.clear();
                        }
                    }
                }
            }
            /* Count the remaining words in the list
             *  (last lines of the file do perhaps not fill up until the given SIZE, therefore need to be counted here)
             *  Fill the list with empty items if the size of the list does not match with the given SIZE */
            while (results.size() != SIZE) {
                results.add("");
            }
            arrayBlockingQueueInput.put(results);
            List<String> list = new ArrayList<String>();
            list.add(HALT);
            arrayBlockingQueueInput.put(list);
            results.clear();
        } catch (InterruptedException e) {
            producerIsRunning = false;
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Main Class: 主类:

public void main() throws IOException, InterruptedException {
    System.out.println("Enter the word you want to find: ");
    Scanner scan = new Scanner(System.in);
    findWord = scan.nextLine();

    System.out.println("Starting...");
    long startTime = System.currentTimeMillis();
    Thread producer = new Thread(new Producer());
    producer.start();
    ExecutorService executorService = Executors.newFixedThreadPool(CORE);

    List<Future<Integer>> futureResults = new ArrayList<Future<Integer>>();

    for (int i = 0; i < CORE; i++) {
        futureResults.add(executorService.submit(new Consumer()));
    }

    executorService.shutdown();

    for (Future<Integer> result : futureResults) {
        try {
            wordsInText += result.get();
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    producer.join();

    long stopTime = System.currentTimeMillis();

    System.out.println("The word " + findWord + " appears " + wordsInText + " times in the given text");

    System.out.println("Elapsed time was " + (stopTime - startTime) + " milliseconds.");
}

Can anybody explain why this happends? 任何人都可以解释为什么会这样吗? I would like to add that we try to use a poison pill to notify the consumers that the producer is on HALT. 我想补充一点,我们尝试使用毒丸来通知消费者生产者是在HALT上。

To answer the question why we want to do this like this? 要回答这个问题我们为什么要这样做呢? For school we try to parallelize a certain programming problem. 对于学校,我们尝试并行化某个编程问题。 The problem we chose is string matching. 我们选择的问题是字符串匹配。 We first made a serial solution and a parallel solution. 我们首先制作了串行解决方案和并行解决方案。 For the next assignment we have to improve our parallel solution and our teacher told us that this is a way to do it. 对于下一个任务,我们必须改进我们的并行解决方案,我们的老师告诉我们这是一种方法。

Thanks in advance! 提前致谢!

Nick 缺口

You add list to a queue and the clear it: 您将列表添加到队列并清除它:

arrayBlockingQueueInput.put(results);
results.clear();

You need to do something like this to add copy of list to a queue so that clear() will not clean list which is in queue: 您需要执行以下操作以将列表副本添加到队列中,以便clear()不会清除队列中的列表:

arrayBlockingQueueInput.put(new ArrayList<String>(results));
results.clear();

After some help from my teacher he helped us find the problem. 在老师的帮助下,他帮我们找到了问题。 There were two mistakes. 有两个错误。 One was within the producer class. 一个是生产者类。 I had code to signal a HALT of the producer within the main while loop. 我有代码在主while循环中发出生产者的HALT信号。 This should not have been done. 这不应该做。

Besides this, the .take() I do within the Consumer class before the Do-While should have been done within the do-while loop. 除此之外,我在Do-While之前在Consumer类中执行的.take()应该在do-while循环中完成。

The correct code looks like this: 正确的代码如下所示:

Consumer class: 消费者阶层:

public static class Consumer implements Callable<Integer> {

    int count = 0;

    @Override
    public Integer call() throws Exception {
        List<String> list = new ArrayList<>();
        do {
            list = arrayBlockingQueueInput.take();
            if (!list.get(0).equals(HALT)){
                for (int i = 0; i < list.size(); i++) {
                    for (String element : list.get(i).split(" ")) {
                        if (element.equalsIgnoreCase(findWord)) {
                            count++;
                        }
                    }
                }
            } else {
                arrayBlockingQueueInput.put(list);
            }
        } while (!list.get(0).equals(HALT));
        return count;
    }
}

Producer class: 制片人类:

public static class Producer implements Runnable {

    @Override
    public void run() {
        try {
            FileReader file = new FileReader("src/testText.txt");
            BufferedReader br = new BufferedReader(file);

            while ((textLine = br.readLine()) != null) {

                if (textLine.isEmpty()) {
                    continue;
                }

                /* Remove punctuation from the text, except of punctuation that is useful for certain words.
                * Examples of these words are don't or re-enter */
                textLine = textLine.replaceAll("[[\\W]&&[^']&&[^-]]", " ");

                /* Replace all double whitespaces with single whitespaces.
                * We will split the text on these whitespaces later */
                textLine = textLine.replaceAll("\\s\\s+", " ");

                textLine = textLine.replaceAll("\\n", "").replaceAll("\\r", "");

                if (results.isEmpty()) {
                    results.add(textLine);
                    continue;
                }
                if (results.size() <= SIZE) {
                    results.add(textLine);
                    if (results.size() == SIZE) {
                        arrayBlockingQueueInput.put(new ArrayList<String>(results));
                        results.clear();
                    }
                }
            }
            /* Count the remaining words in the list
             *  (last lines of the file do perhaps not fill up until the given SIZE, therefore need to be counted here)
             *  Fill the list with empty items if the size of the list does not match with the given SIZE */
            while (results.size() != SIZE) {
                results.add("");
            }
            arrayBlockingQueueInput.put(new ArrayList<String>(results));
            List<String> list = new ArrayList<String>();
            list.add(HALT);
            arrayBlockingQueueInput.put(list);
            results.clear();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Main class: 主要课程:

public void main() throws IOException, InterruptedException {
    System.out.println("Enter the word you want to find: ");
    Scanner scan = new Scanner(System.in);
    findWord = scan.nextLine();

    System.out.println("Starting...");
    long startTime = System.currentTimeMillis();
    Thread producer = new Thread(new Producer());
    producer.start();
    ExecutorService executorService = Executors.newFixedThreadPool(CORE);

    List<Future<Integer>> futureResults = new ArrayList<Future<Integer>>();

    for (int i = 0; i < CORE; i++) {
        futureResults.add(executorService.submit(new Consumer()));
    }

    executorService.shutdown();

    for (Future<Integer> result : futureResults) {
        try {
            wordsInText += result.get();
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    producer.join();

    long stopTime = System.currentTimeMillis();

    System.out.println("The word " + findWord + " appears " + wordsInText + " times in the given text");

    System.out.println("Elapsed time was " + (stopTime - startTime) + " milliseconds.");
}

Thanks to @Ivan for helping me with the .clear method called on results. 感谢@Ivan帮助我使用.clear方法调用结果。 Without this the code solution did not work. 没有这个,代码解决方案就不起作用了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的结果列表为空? - Why my result list is empty? 为什么在捕获InterruptedException之后ArrayBlockingQueue信号“未满”? - Why does ArrayBlockingQueue signal 'not full' after catching InterruptedException? 为什么我的方法打印一个空列表? - Why does my method print an empty list? 为什么调用返回列表,打印空列表的方法? - Why does my call to a method that returns a list, print an empty list? 为什么ArrayBlockingQueue被称为有界队列而LinkedBlockingQueue被称为无界阻塞队列? - Why the ArrayBlockingQueue is called a bounded queue while a LinkedBlockingQueue is called an unbounded blocking queue? 为什么即使放置正确的键值后,我的HashMap.get也返回空值? - Why does my HashMap.get returns null value even after putting proper key,value? 为什么ArrayBlockingQueue使用数组删除内部缓冲区? - Why does ArrayBlockingQueue use arrays for interior buffer removal? 为什么我的 if 链表空语句不是 output 什么? - Why does my if linked list empty statement not output anything? 为什么我的列表需要会话中的空列表才能显示添加到该列表的所有项目? - Why does my list need an empty list from session in order to show all the items added to that list? 为什么GridBagLayout集中我的组件而不是把它放在角落? - Why does GridBagLayout center my components instead of putting it in the corner?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM