0

我遇到了以下问题:我已经实现了一个爬虫,我想知道上一秒完成了多少请求,最后一秒下载了多少数据。

目前,我已经使用锁实现了它。我的版本使用一个队列和两个计数器(计数和总和)。当任务完成时,我只是增加我的计数器,然后我将一个事件(与当前日期)添加到队列中当想要获取我的计数器的值时,我检查队列中的某些内容是否超过 1 秒。如果是这样,我将它出列并适当地减少我的计数器。然后,我返回想要的结果。

这个版本运行良好,但出于培训目的,我想使用原子操作而不是锁来重新实现它。尽管如此,我不得不承认我被困在“清洁行动”上。(旧值的出列)

那么,这是实现这个的好方法吗?

我可以使用哪种其他方法?

谢谢 !

4

1 回答 1

1

这个版本运行良好,但出于培训目的,我想使用原子操作而不是锁来重新实现它。

如果在滚动期发生时需要对数据进行多次更改,则需要锁定,否则会出现问题。任何时候你有多个“原子操作”,你都需要一个锁来防止竞争条件。例如,在您的情况下,如果在您滚动时将其他内容添加到队列中怎么办?

我可以使用哪种其他方法?

我不是 100% 确定您为什么需要将信息排队。如果您只计算请求数和下载的数据总大小,那么您应该能够使用单个AtomicReference<CountSum>. 该类CountSum将存储您的两个值。然后,当有人需要增加它时,他们会执行以下操作:

CountSum newVal = new CountSum();
do {
   CountSum old = countSumRef.get();
   newVal.setCount(old.getCount() + 1);
   newVal.setSum(old.getSum() + requestDataSize);
   // we need to loop here if someone changed the value behind our back
} while (!countSumRef.compareAndSet(old, newVal));

这可确保您的计数和总和始终保持同步。如果您使用了两个AtomicLong变量,则必须发出两个原子请求并且再次需要锁。

当你想重置这些值时,你会做同样的事情。

CountSum newVal = new CountSum(0, 0);
CountSum old;
do {
   old = countSumRef.get();
   // we need to loop here if someone changed the value behind our back
} while (!countSumRef.compareAndSet(old, newVal));
// now you can display the old value and be sure you got everything
于 2013-11-01T17:58:35.623 回答