从LinkedBlockingQueue中删除元素时,我的下面的代码线程是否安全?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从LinkedBlockingQueue中删除元素时,我的下面的代码线程是否安全?相关的知识,希望对你有一定的参考价值。

我有一个下面的方法,由多个线程同时调用以获取实时套接字。它需要LinkedBlockingQueue作为参数,然后我迭代,看看是否有任何可用的liveSocket,如果它可用,那么我删除并返回该套接字。

  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);
    }
}

如果你用LinkedList替换LinkedBlockingQueue,你会得到预期的ConcurrentModificationException

输出:

a
b
added
c
removed
d
f
g
x
另一答案

它不仅不是线程安全的,即使在单个线程中也是错误的。你会在ConcurrentModificationException上得到一个remove()。你需要使用一个明确的Iterator并通过Iterator进行删除。

并且为了通过多个线程获得正确性,您需要在循环周围进行同步或信号量。

NB isEmpty()测试毫无意义。迭代已经必须检查它。不要养狗和自己吠叫。

以上是关于从LinkedBlockingQueue中删除元素时,我的下面的代码线程是否安全?的主要内容,如果未能解决你的问题,请参考以下文章

阻塞队列之LinkedBlockingQueue

LinkedBlockingQueue与ArrayBlockingQueue

LinkedBlockingQueue 与ConcurrentLinkedQueue队列的不同与同

Java阻塞队列实现原理分析-ArrayBlockingQueue和LinkedBlockingQueue

ArrayBlockingQueue和LinkedBlockingQueue

LinkedBlockingQueue put vs offer