4

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

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

List<Object> list = Collections.synchronizedList(new LinkedList<>());

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

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

我忽略了任何解决方案?


编辑:

使用LinkedList. 我看到有些人正在提议其他系列。所以,这里遵循简短的要求,这导致我决定使用LinkedList.

更多背景信息:

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

2 回答 2

5

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

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

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

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

这带来了一个问题,因为您的列表有时会在peek和之间发生变化pop(上面代码中的这个地方被标记为“问题”)。

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

synchronized(list) {
    String s = list.peek();
    if (s != null) {
        s = list.pop();
    }
}

然而,这不能在一个简单的包装器中完成,因为两个列表操作是在一个synchronized块中执行的。

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

于 2015-11-20T16:59:35.800 回答
5

你想要的是一个并发的Queue. LinkedList实现List,DequeQueue. 这Queue就是它赋予它具有 peek 和 pop 的 FIFO(从前面添加,从前面删除)语义的原因。

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

于 2015-11-20T17:01:14.710 回答