【问题标题】:Problems implementing BlockingQueue from scratch从头开始实施 BlockingQueue 的问题
【发布时间】:2016-11-10 19:13:48
【问题描述】:

我正在尝试基于 found here 构建我自己的 BlockingQueue 变体。

public class ThreadSafeContainer<E> {
private Node front;
private Node end;
private int capacity;
private int size;

public ThreadSafeContainer(int capacity) {
    size = 0;
    this.capacity = capacity;
}

public synchronized void add(E item) {
    while (size == capacity) {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    if (size == 0) {
        notifyAll();
    }

    Node tmp = new Node(item);

    if (end == null) {
        front = tmp;
        end = tmp;
    } else {
        end.next = tmp;
        end = end.next;
    }

    size++;
}

public synchronized E remove() {
    while (size == 0) {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    if (size == capacity) {
        notifyAll();
    }

    E item = front.item;
    front = front.next;
    size--;
    return item;
}

private class Node {
    E item;
    Node next;

    public Node(E item) {
        this.item = item;
    }
}

但由于某种原因,当我尝试像这样运行线程时

    Thread thread1 = new Thread() {
        public void run() {
            queue.add(1);
            queue.add(2);
        }
    };

    Thread thread2 = new Thread() {
        public void run() {
            System.out.println(queue.remove());
            System.out.println(queue.remove());
        }
    };      

我得到了这个异常

线程“Thread-3”中的异常 java.lang.NullPointerException 在 ThreadSafeContainer.remove(ThreadSafeContainer.java:52) 在 ThreadPractice$2.run(ThreadPractice.java:17) 在 java.lang.Thread.run(Unknown Source)

我可以通过将 size == 0 更改为 front == null 来消除错误,但它仍然不会输出相同的内容。

【问题讨论】:

  • @bradimus 从功能上讲,我的代码应该具有相同的行为,除了使用我自己设计的预先存在的列表结构。 size++/-- 应该反映我使用的示例的效果。但是他的运行良好,而我的有错误。

标签: java multithreading synchronization blockingqueue


【解决方案1】:

目前,如果对remove() 的调用删除了最后一个元素,您最终会得到front == nullend == //the last created node。这意味着对add 的下一次调用只会更新end,而不是front,并且对remove() 的相应调用将抛出你的NPE。

您可以在remove() 的末尾检查front == null,或者将add 中的测试从end == null 更改为size == 0front == null

顺便说一句,如果您要发布堆栈跟踪,添加注释以指示您的 sn-p 中的哪一行对应于异常中的行号会很有帮助。

【讨论】:

    猜你喜欢
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 2011-04-15
    相关资源
    最近更新 更多