从LinkedBlockingQueue中删除元素时,我的下面的代码线程安全吗?
我有一个下面的方法,它被多个线程同时调用来获取活动套接字。它需要LinkedBlockingQueue
作为参数,然后我迭代,看看是否有liveSocket可用,如果它可用,然后我删除并返回该套接字。从LinkedBlockingQueue中删除元素时,我的下面的代码线程安全吗?
private Optional<Holder> getSocket(final LinkedBlockingQueue<Holder> endPoints) { Optional<Holder> liveSocket = Optional.absent();
if (!endPoints.isEmpty()) {
for (Holder state : endPoints) {
// check if socket is live? if yes then remove and return that.
if (state.isLive()) {
liveSocket = Optional.of(state);
endPoints.remove(state);
return liveSocket;
}
}
}
return Optional.absent();
}
想检查我的上面的代码是否线程安全?这里Holder
是一个不可变的类。
回答:
队列操作操作是线程安全的,所以remove()
不会抛出ConcurrentModificationException
。但是,您在队列中包含的对象状态周围存在线程安全问题。
当您检查Holder
对象的“活动”状态以及将其从队列中删除时,存在竞争状态。另一个线程可能同时在相同的代码中运行,可能的结果是两个线程都会采用同一个对象。无论哪个线程到达remove()
最后会得到一个false
回报,但是您不检查结果,所以你永远不会知道。两个线程都会尝试使用同一个对象。
您需要围绕搜索/删除操作进行同步。
出于好奇,这里是我用来证明ConcurrentModificationException
不LinkedBlockingQueue
发生代码:
public static void main(String[] args) throws Exception {
String[] data = { "a", "b", "c", "d", "e", "f","g" };
LinkedBlockingQueue<String> lb = new LinkedBlockingQueue<>(Arrays.asList(data));
new Thread(() ->
{
try
{
Thread.sleep(2000);
lb.add("x");
System.out.println("added");
Thread.sleep(1000);
lb.remove("e");
System.out.println("removed");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}).start();
for (String s : lb)
{
System.out.println(s);
Thread.sleep(1000);
}
}
如果您LinkedBlockingQueue
代替LinkedList
你得到预期的ConcurrentModificationException
。
输出:
a b
added
c
removed
d
f
g
x
回答:
它不仅不是线程安全的,甚至在单个线程中也是错误的。您将在remove()
上获得ConcurrentModificationException
。您需要使用明确的Iterator
并通过Iterator
进行删除。
并且为了通过多线程的正确性,您需要在循环周围实现同步或信号量。
NB isEmpty()
测试毫无意义。迭代已经必须检查。不要养狗,吠叫自己。
以上是 从LinkedBlockingQueue中删除元素时,我的下面的代码线程安全吗? 的全部内容, 来源链接: utcz.com/qa/260724.html