java.util.Stack或java.util.Queue有什么线程安全问题

时间:2014-08-03 18:10:01

标签: java

如果我忽略了size()的不准确性,并假设我分配了足够大的底层Vector,以便不会发生重新分配,java.util.Stack或java.util.Queue会遇到什么线程安全问题?

我无法想到一个有效/合理的一致性论点,说它们是线程不安全的。

有人有一些见解吗?

3 个答案:

答案 0 :(得分:5)

"线程安全"并非属于某个类的绝对属性 - 对象的用法的安全性或不安全性。您可以采用不安全的方式来使用ConcurrentHashMap,并且可以使用线程安全的方式来使用普通HashMap

当人们说一个类是线程安全的时,它们通常意味着每个方法都是以一种线程安全的方式实现的。从这个意义上说,Stack是线程安全的。但是它的界面不允许轻松/安全地处理常见用例,因此从这个意义上说它非常线程安全。

例如,如果您的代码检查Stack不是空的,如果是,则弹出一个元素 - 这是不安全的,因为它可能是因为它有一个元素(因此不是空的),但是有其他人在你有机会之前弹出它(在这种情况下你会尝试弹出一个空堆栈,并且会得到一个例外)。

为了更加线程安全,你真的需要一个能够为你处理这种情况的方法。 BlockingQueue给你一个。例如,take()会阻止直到弹出值,而poll()会立即返回一个值,如果没有要弹出的元素,则会null。< / p>

答案 1 :(得分:1)

扩展Stack

Vector让每个方法都同步。这意味着与各个方法的交互是线程安全的。

Queue是一个界面。跨线程使用的安全性取决于各个实现。例如,ArrayBlockingQueue是线程安全的,但LinkedList不是。

答案 2 :(得分:0)

从ArrayBlockingQueue看一下这个方法(不管任何现有的同步):

private void insert(E x) {
    items[putIndex] = x; 
    // HERE
    putIndex = inc(putIndex);
    ++count;
    notEmpty.signal();
}

让线程A进展到HERE,让线程B接管并执行该方法;然后让A继续。很容易看出B&#39; E x覆盖A E x,计数增加2,putIndex增加两次。

类似的HERE也可以在其他方法中找到。

所有带有内存的数据和记账变量的数据结构都明显容易受到未同步访问的影响。