public class BQueue<T> {
private Queue<T> q = new LinkedList<T>();
private int limit;
public BQueue(int limit) {
this.limit = limit;
}
public synchronized void put (T t) throws InterruptedException {
while (isFull()) {
wait();
}
boolean e = isEmpty();
q.add(t);
if (e)
notifyAll();
}
public synchronized T get () throws InterruptedException {
while (isEmpty()) {
wait();
}
boolean f = isFull();
T t = q.poll();
if (f)
notifyAll();
return t;
}
private boolean isEmpty() {
return q.size() == 0;
}
private boolean isFull() {
return q.size() == limit;
}
}这个实现线程安全吗?
发布于 2011-12-19 21:38:19
是的,它是线程安全的。(至少我没有发现任何问题。)请注意,Java框架已经有了一个BlockingQueue接口,它有一些实现,例如LinkedBlockingQueue (来源)。它可能测试得很好,add有更好的性能,所以如果没有必要的话,尽量不要重新发明轮子。
其他一些注意事项:
isFull,这样可以产生更易读的代码。q和t也是如此。(我会把它重命名为queue和item。)limit是0或小于零时会发生什么?(您应该抛出一个IllegalArgumentException。)limit和q字段可以标记为final。这将提高代码的可读性,因为读取器不需要检查它们的值是否在类中的某个地方发生了变化。它还将防止意外的价值修改。Queue有一个isEmpty方法(通过实现Collection.isEmpty()),您可以使用它而不是自己的方法。发布于 2012-01-26 16:54:51
我觉得这挺安全的。然而,我对驱动通知的逻辑感到困惑。
在put()中,等待队列非满(即至少打开一个时隙),然后将元素t添加到队列的末尾。酷,但是在添加t之前,只有当队列为空时才会通知其他线程。类似地,在get()中,您等待队列非空(即至少有一个项),然后从队列的头获取元素t。同样,很酷,但是只有当队列在获取t之前已满时,才会通知其他线程。这样做的效果是要求队列在清空前被完全填满,反之,在重新填充队列之前将其完全清空。
也许这就是你的意图,但这并没有在行为中被记录下来,也不是典型的阻塞队列。
我想你可能想要的是:
public synchronized void put (T t) throws InterruptedException {
while (isFull())
wait();
q.add(t);
notifyAll();
}以及:
public synchronized T get () throws InterruptedException {
while (isEmpty())
wait();
T t = q.poll();
notifyAll();
return t;
}此版本的put()将在添加新元素后立即通知等待线程。这将唤醒所有等待的get()调用,并立即获取您刚才添加的值。这通常是你想要的。如果任何其他等待的put()调用醒来后发现队列已满(因为您刚刚在可能等待它为非满之后添加了一个元素),它将简单地在while循环中循环并开始再次等待;没有造成任何伤害。
类似地,此版本的get()将在删除元素后立即通知等待线程。这将立即唤醒所有等待的put()调用,并允许它们存储新值。这通常也是你想要的。如果任何其他等待的get()调用醒来后发现队列是空的(因为您可能刚刚删除了最后一个元素),它将简单地在while循环中循环,然后再次开始等待,直到其他人添加了另一个元素。
除此之外,在我看来还不错!
附注:-由于get()和put()是同步的,所以在从队列中实际删除项之前调用notifyAll()没有什么害处,因为其他等待线程在退出get()之前实际上无法再次运行(因为您没有等待)。因此,它可以进一步简化:
public synchronized T get () throws InterruptedException {
while (isEmpty())
wait();
notifyAll();
return q.poll();
}发布于 2011-12-19 19:46:07
在我看来它是安全的。但不要相信我的话,你最好把每一个答案都当作一张选票,按照大多数人说的去做。(多线程是很棘手的!)注:评论不应被视为答案。
https://codereview.stackexchange.com/questions/7002
复制相似问题