我有一个类,其中多个线程调用我的add
方法来填充clientidToTimestampHolder
LinkedBlockingQueue。然后在同一个下面的类中,我有一个后台线程,它每30毫秒运行一次并调用processData()
方法将clientidToTimestampHolder
排到Map of Map,然后迭代该List以将数据发送到不同的服务通过调用适当的方法。
我可以使用不同的时间戳多次获得相同的用户ID,这就是我使用LinkedBlockingQueue
和地图的原因。
public class Handler {
private final ScheduledExecutorService executorService = Executors
.newSingleThreadScheduledExecutor();
private final LinkedBlockingQueue<Map.Entry<String, Long>> clientidToTimestampHolder =
new LinkedBlockingQueue<>();
private static class Holder {
private static final Handler INSTANCE = new Handler();
}
public static Handler getInstance() {
return Holder.INSTANCE;
}
private Handler() {
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
processData();
}
}, 0, 30, TimeUnit.MILLISECONDS);
}
// called by multiple threads to populate clientidToTimestampHolder map
public void add(final String clientid, final Long timestamp) {
clientidToTimestampHolder.offer(Maps.immutableEntry(clientid, timestamp));
}
// called by single background thread every 30 milliseconds
public void processData() {
final List<Map.Entry<String, Long>> entries = new ArrayList<>();
clientidToTimestampHolder.drainTo(entries);
for (Map.Entry<String, Long> entry : entries) {
String clientid = entry.getKey();
long timestamp = entry.getValue();
boolean isUpdated = isUpdatedClient(clientid, timestamp);
if (!isUpdated) {
updateClient(String.valueOf(clientid));
}
}
}
}
我的上述代码线程是否安全并且没有竞争条件,我不会错过processData()
方法中的任何数据?由于add
方法将从多个线程调用,然后我有一个后台线程,每30毫秒运行一次,调用processData()
方法从clientidToTimestampHolder
LinkedBlockingQueue中提取数据。
答案 0 :(得分:1)
匿名类包含对外部类的this
引用(即Handler
)。在最终字段冻结之前,您已经不安全地发布了this
引用,执行程序的线程在读取时可能看不到正确初始化的集合。
除此之外,我不知道processData
将如何错过任何更新。如果排出操作没有捕获并发写入,则不会在下次运行时进行。除非你担心这个(在这种情况下,你需要锁定),只要你不修改集合,它对我来说就好了。
另一方面,String#valueOf
对字符串的目的是什么?