LinkedList
具有方便的peek
、pop
。。。方法
不幸的是,我需要一个线程安全的LinkedList
。因此,我的第一个想法是将其包装如下:
List<Object> list = Collections.synchronizedList(new LinkedList<>());
但是,由于List
接口不包含peek
或pop
方法。这当然行不通。
或者,我可以在整个代码中使用synchronized(list)
块。这是要走的路吗?
有没有我忽略的解决方案?
编辑:
使用LinkedList
的原因有很多。我看到有些人在提议其他的收藏品。因此,这里遵循简短的要求,这导致我决定使用LinkedList
。
更多背景信息:
- 我正在使用LinkedList,因为这些项目需要订购
- 应以非阻塞方式添加项目
- 项目添加在后面;从前面拆下
- 在移除第一个项目之前,首先需要对其进行
peek
编辑和验证。如果验证失败,则该项目需要保留在列表中 - 只有验证成功完成,才会删除第一个项目
- 队列需要具有最大大小(以避免内存问题)
如果您需要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
块中执行两个列表操作。
通过构建自己的数据结构来封装LinkedList<T>
,并提供在同步块中执行所有测试和修改操作的操作,可以避免在多个位置编写synchronized
。然而,这不是一个简单的问题,因此您最好更改算法,使其能够与预定义的并发容器之一一起工作。
您想要的是一个并发的Queue
。LinkedList
实现List
、Deque
和Queue
。Queue
赋予了它带有peek和pop的FIFO(添加到后面,从前面移除)语义。
LinkedBlockingQueue可以是有界的,这是您的标准之一。还有其他几个并发队列和Deques可供选择。