【问题标题】:java linkedlist returns same element multi threadjavalinkedlist返回相同元素多线程
【发布时间】:2015-03-30 19:38:27
【问题描述】:

我想将 PacketHandler 读取的 Packets 添加到 LinkedList 中 保存它们:

Packet toAdd = handler.handlePacket(socket.getInputStream());
synchronized (packetsRead) {
    packetsRead.addLast(toAdd);
    if (debug) {
       System.out.println(packetsRead.getLast().toString());
    }
}

和阅读它们

synchronized (packetsRead) {
    if (packetsRead.size() > 0) {
        return packetsRead.pollFirst();
    }
}

使用第一种方法中的调试方法,我可以看到 最后一项永远不会相同。所以不同的数据包被添加到我的列表中。

但是当我尝试从不同的线程读取它们时,我总是得到相同的数据包。

例如,如果我的列表中有 10 个不同的数据包,它将返回第一个数据包 10 次。

如何使其线程安全?

【问题讨论】:

  • 为什么不使用线程安全的实现? stackoverflow.com/questions/12043948/…
  • 我在同一个对象上同步了它,为了测试目的,我把它改成了这个。对不起
  • 如何访问阅读线程中的列表 - 您确定不是每次都复制列表以始终获得第一项吗?
  • 我认为它不能是列表的副本,因为它只会返回与队列中元素相同的元素
  • 请显示packetsRead 的定义并解释它的任何其他用法,您的代码在这里看起来不错。

标签: java multithreading linked-list thread-safety synchronized


【解决方案1】:

代码必须在相同的对象上同步。

如果这样做了 - 并且程序的其余部分正确,并且这是访问 LinkedList 的唯一位置 - 那么无论有没有线程,它都会按预期工作。如果使用同一个对象,同步块不够大,贴出的代码也没有问题。

FWIW:请参阅 Matt 的回答,了解一些替代的线程安全设计数据结构。但请注意,如果问题不是使用相同的同步对象,这些将解决问题。

【讨论】:

  • 在同一个对象上同步它仍然无法工作:/ 我将尝试使用 LinkedBlockingQueue 或 synchronizedList
  • 那么您没有显示损坏的代码和/或对链接列表的所有访问 - 切换到另一个结构将不会解决问题,它没有使用大足够的线程安全区域/构造。
  • 好吧,我告诉过你,我正在从另一个线程读取数据,并且“pollFirst”总是返回同一个对象。我出于测试原因将其更改为 Packet answer = packetRead.pollFirst(); System.out.println(answer.toString());返回答案;它总是一样的
  • @Michii 所以有三个可能的原因 1)代码没有在同一个对象上同步 2)不是受影响的代码; 3) 相同的“答案”对象正在被修改和/或共享(或测试存在其他问题),使其看起来“始终相同”。切换数据结构对#2 或#3 没有帮助。确保发布最少的 SSCCE
【解决方案2】:

不要将普通的LinkedList 用于并发目的:

注意这个实现是不同步的。如果多个线程同时访问一个链表,并且至少有一个线程在结构上修改了链表,它必须是同步的外部。

至少,按照the LinkedList JavaDocs 中的描述使用Collections.synchronizedList()

更好的是:使用线程安全的并发数据结构,例如 ConcurrentLinkedQueueArrayBlockingQueueLinkedBlockingQueue

【讨论】:

  • 虽然这些会起作用,但它并不能解决问题。
猜你喜欢
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 2020-05-25
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多