同步链表 - peek

bvd*_*vdb 5 java linked-list thread-safety peek

ALinkedList方便的peek, pop, ... 方法。

不幸的是,我需要一个线程安全的LinkedList. 所以,我的第一个想法是将其包装如下:

List<Object> list = Collections.synchronizedList(new LinkedList<>());
Run Code Online (Sandbox Code Playgroud)

但是,由于该List接口不包含peekpop方法。这当然行不通。

或者,我可以synchronized(list)在整个代码中使用块。这是要走的路吗?

我忽略了任何解决方案吗?


编辑:

人们使用LinkedList. 我看到有些人正在推荐其他系列。因此,这里遵循简短的要求,这导致我决定使用LinkedList.

更多背景信息:

  • 我使用 LinkedList 因为项目需要排序。
  • 应以非阻塞方式添加项目。
  • 项目添加在后面;从前面移除。
  • 在删除第一项之前,首先需要对其进行peek编辑和验证。如果验证失败,则该项目需要保留在列表中。
  • 仅当验证成功完成时,第一项才会被删除。
  • 队列需要有最大大小(以避免内存问题)。

das*_*ght 5

如果您需要peek工作,制作同步包装器可能还不够,因此您必须synchronized显式编写。

与其说是编写包装器的问题,不如说是方法语义的问题peekpop与表示单个操作的方法不同,peek方法通常用于由 -ing 组成的多组件操作peek,然后根据peek返回的内容执行其他操作。

如果您在包装器中进行同步,则结果将与手动编写此代码相同:

String s;
synchronized(list) {
    s = list.peek();
}
// <<== Problem ==>>
if (s != null) {
    synchronized(list) {
        s = list.pop();
    }
}
Run Code Online (Sandbox Code Playgroud)

这提出了一个问题,因为有时您的列表可能会在 和 之间发生变化peekpop上面代码中的这个地方被标记为“问题”)。

进行检查和修改的正确方法是在单个块中进行synchronized,即

synchronized(list) {
    String s = list.peek();
    if (s != null) {
        s = list.pop();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这无法在简单的包装器中完成,因为两个列表操作是在单个synchronized块中执行的。

您可以synchronized通过构建自己的数据结构来避免在多个位置进行写入,该数据结构封装LinkedList<T>, 并提供在同步块中执行所有测试和修改操作的操作。然而,这不是一个简单的问题,因此您最好更改算法,使其可以与预定义的并发容器之一一起使用。


Law*_*pin 5

你想要的是并发QueueLinkedList实现ListDeque、 和Queue。这Queue就是赋予它 FIFO(在后面添加,从前面删除)语义以及 peek 和 pop 的原因。

LinkedBlockingQueue可以是有界,这是您的标准之一。还有其他几个并发队列和双端队列可供选择。