Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
遍历匹配突变时有效的线程安全Java列表impl_Java_Multithreading_List_Concurrency_Thread Safety - Fatal编程技术网

遍历匹配突变时有效的线程安全Java列表impl

遍历匹配突变时有效的线程安全Java列表impl,java,multithreading,list,concurrency,thread-safety,Java,Multithreading,List,Concurrency,Thread Safety,我有许多线程将使用来自代理的消息并对其进行处理。每个消息都是XML,其中包含字母数字WI354DE48元素,作为要“处理”的项的唯一ID。由于我无法控制或更改的条件,这些线程使用的代理队列上的项目/消息可能会重复。因此,同一个项目(ID为WI354DE48)可能只发送到队列一次,或者发送100次。无论如何,我只能允许该项目处理一次;所以我需要一种方法来防止线程a处理线程B已经处理过的重复项 我希望使用一个简单的线程安全列表,它可以被所有线程(工作线程)共享,作为缓存机制。每个线程都将获得一个相同

我有许多线程将使用来自代理的消息并对其进行处理。每个消息都是XML,其中包含字母数字
WI354DE48
元素,作为要“处理”的项的唯一ID。由于我无法控制或更改的条件,这些线程使用的代理队列上的项目/消息可能会重复。因此,同一个项目(ID为WI354DE48)可能只发送到队列一次,或者发送100次。无论如何,我只能允许该项目处理一次;所以我需要一种方法来防止线程a处理线程B已经处理过的重复项

我希望使用一个简单的线程安全列表,它可以被所有线程(工作线程)共享,作为缓存机制。每个线程都将获得一个相同的
列表实例
。当每个工作线程使用一条消息时,它会检查列表中是否存在
itemId
(一个字符串)。如果没有,则没有其他工作人员处理该项。在这种情况下,将
itemID
添加到列表中(锁定/缓存它),然后处理该项。如果列表中已经存在
itemId
,那么另一个工作人员已经处理了该项,因此我们可以忽略它。简单而有效

显然,有一个线程安全的列表实现是至关重要的。请注意,我们在此列表中唯一调用的两种方法是:

  • List#包含(字符串)
    -遍历/搜索列表
  • List#添加(字符串)
    -更改列表
…值得注意的是,我们将以大约相同的频率调用这两个方法。很少会
contains()
返回
true
并阻止我们需要
添加
ID

我最初认为,
CopyOnWriteArrayList
是我最好的选择,但在阅读了Javadocs之后,似乎每个工作人员都会得到自己的线程本地列表副本,这不是我想要的。然后我查看了集合。synchronizedList(新ArrayList),这似乎是一个不错的赌注:

List<String> processingCache = Collection.synchronizedList(new ArrayList<String>());
List<Worker> workers = getWorkers(processingCache); // Inject the same list into all workers.
for(Worker worker : workers)
    executor.submit(worker);

// Inside each Worker's run method:
@Override
public void run() {
    String itemXML = consumeItemFromBroker();
    Item item = toItem(itemXML);

    if(processingCache.contains(item.getId())
        return;
    else
        processingCache.add(item.getId());

    ... continue processing.
}
List processingCache=Collection.synchronizedList(new ArrayList());
List workers=getWorkers(processingCache);//将相同的列表注入所有工作人员。
用于(工人:工人)
执行人提交(工人);
//在每个辅助人员的运行方法中:
@凌驾
公开募捐{
字符串itemXML=consumeItemFromBroker();
Item=toItem(itemXML);
if(processingCache.contains(item.getId())
返回;
其他的
processingCache.add(item.getId());
…继续处理。
}

我是否正在使用
集合。synchronizedList(新ArrayList)
,或者我是否偏离了基准?根据我的用例,是否有更有效的线程安全
列表
impl,如果是,原因是什么?

集合。synchronizedList
非常基本,它只是将所有方法标记为
已同步

这将起作用,但仅在某些特定的假设下,即您从未多次访问
列表
,即

if(!list.contains(x))
    list.add(x);
在两次调用之间释放监视器时,不是线程安全的

当所有线程都获得一个排他锁时,如果读多写少,也会有点慢

您可以查看包中的实现,有几个选项

我建议使用带有虚拟值的

推荐的原因是,
ConcurrentHashMap
具有同步的密钥组,因此如果您有一个好的哈希算法(并且
String
有),您实际上可以获得大量的并发吞吐量

我更喜欢这个而不是一个
ConcurrentSkipListSet
,因为它不能保证订购,因此您会失去这种开销


当然,对于线程来说,瓶颈所在的位置从来都不是很明显,因此我建议尝试这两种方法,看看哪一种可以提供更好的性能。

集合。synchronizedList
非常基本,它只是将所有方法标记为
synchronized

这将起作用,但仅在某些特定的假设下,即您从未多次访问
列表
,即

if(!list.contains(x))
    list.add(x);
在两次调用之间释放监视器时,不是线程安全的

当所有线程都获得一个排他锁时,如果读多写少,也会有点慢

您可以查看包中的实现,有几个选项

我建议使用带有虚拟值的

推荐的原因是,
ConcurrentHashMap
具有同步的密钥组,因此如果您有一个好的哈希算法(并且
String
有),您实际上可以获得大量的并发吞吐量

我更喜欢这个而不是一个
ConcurrentSkipListSet
,因为它不能保证订购,因此您会失去这种开销


当然,对于线程来说,瓶颈所在的位置从来都不是很明显,因此我建议尝试这两种方法,看看哪一种可以提供更好的性能。

看起来您需要一个
集,而不是
列表,基本上就是这句话:很少会包含()返回true并防止我们需要添加ID。最好使用看起来像您需要一个
,而不是一个
列表
,基本上是为了这句话:只会很少包含()返回true并防止我们需要添加ID。最好使用Thank@Boris the Spider(+1)-你能考虑Luiggi Mendoza对
ConcurrentSkipListSet
的建议吗?就性能而言,如何公平地使用
ConcurrentHashMap
?@TicketMonster这将取决于你的需要。进行一些测试,然后由你的团队决定