从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回报,但是您不检查结果,所以你永远不会知道。两个线程都会尝试使用同一个对象。

您需要围绕搜索/删除操作进行同步。

出于好奇,这里是我用来证明ConcurrentModificationExceptionLinkedBlockingQueue发生代码:

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

回到顶部