• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

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

java 来源:user1950349 5次浏览

我有一个下面的方法,它被多个线程同时调用来获取活动套接字。它需要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 

版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)