【问题标题】:Rewrite ConcurrentHashMap compute() and computeIfPresent()重写 ConcurrentHashMap compute() 和 computeIfPresent()
【发布时间】:2021-01-14 19:30:13
【问题描述】:

ConcurrentHashMap 的实现相当复杂,因为它专门设计用于允许并发可读性同时最小化更新争用。在非常高的抽象层次上,它被组织成一个分桶的哈希表。

在移动应用的上下文中,ConcurrentHashMaps 的一个问题是 compute() 和 computeIfPresent() 等函数,它们需要 API 24 (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES. N)

我想知道如何才能满足较低级别的设备,如何重写 compute() 和 computeIfPresent() 以适用于 API23 及以下的设备?

以下是我使用这些功能的一些情况。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            scheduledTasks.compute(uid) { _, oldTask ->
                val newTask = ScheduledTask(uid, runnable, interval, null)
                if (oldTask != null) {
                    oldTask.cancel()
                    requiresRestart.set(oldTask.isScheduled)
                }
                newTask
            }
        } else {
            // TODO Need lower API implementation
        }

在上面的示例中,我正在更新作为 ConcurrentHashMap 的 scheduleTasks。可以创建跨多个线程的多个计划任务。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            return scheduledTasks.computeIfPresent(uid) { _, oldTask ->
                val future = executor.scheduleWithFixedDelay(
                        oldTask.runnable, 0, oldTask.interval.toLong(), TimeUnit.SECONDS)
                ScheduledTask(oldTask.uid, oldTask.runnable, oldTask.interval, future)
            }
        } else {
            // TODO Need lower API implementation
            return null
        }

【问题讨论】:

  • 感谢您的回答。我实际上已经在我的 gradle 中启用了它。但这并不能使我的代码与低于 API 24 的设备兼容。这是我的问题。抱歉,如果不清楚。
  • 但确实如此。阅读文档:“该插件扩展了对使用多种 Java 8 语言 API 的支持,而无需为您的应用设置最低 API 级别。”它支持任何 API 级别。
  • @LouisWasserman 是的,但这不适合我。这实际上是一个 SDK。问题不在于我,而是要求较低的集成商。除非我们强迫他们进行同样的更新,否则这不是我想要的解决方案。例如,我可以重写 compute() 的功能,一般而言,它只是以原子方式更新值,检查重映射函数是否抛出异常,重新抛出异常,并保留当前映射不变,在计算过程中,来自其他线程的地图更新过程被阻塞,等等。我也可以模仿。

标签: android kotlin hashmap concurrenthashmap


【解决方案1】:

我只给出computeIfPresent 的例子,因为compute 非常相似,只是更多的工作。这是在Java中;转换为 Kotlin 并没有什么特别的区别。

 public <K, V> V computeIfPresent(
     ConcurrentMap<K, V> map, K key, BiFunction<? super K, ? super V, ? extends V> f) {
   V currentValue = map.get(key);
   while (currentValue != null) {
     V nextValue = f.apply(key, currentValue);
     if (nextValue == null) {
       if (map.remove(key, currentValue)) {
         return currentValue;
       }
     } else if (map.replace(key, currentValue, nextValue)) {
       return currentValue;
     }
     currentValue = map.get(key);
   }
   return null;
 }

此版本具有适当的原子性保证。

【讨论】:

  • 感谢您的回答。这就是我一直在寻找的。 “f.apply(key, currentValue)”存在问题。 apply() 是一个 API 24 函数。我正在尝试编写比这更低级别的代码。
  • 定义您自己的界面并使用它。这只是一个例子。
  • 我不能在低端设备上调用你的函数,例如,API 22 设备由于 apply() 就是我的意思。有没有办法重写 apply() 函数?其他一切都很好。该 apply() 函数也在原始的 computeIfPresent 中,这就是为什么调用该函数也有 API 24 要求。
  • 实际上,我知道如何重写,所以它可以工作。它只是重新分配和更新值。干杯!
猜你喜欢
  • 1970-01-01
  • 2019-03-25
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
相关资源
最近更新 更多