重写 ConcurrentHashMap compute() 和 computeIfPresent()

Rewrite ConcurrentHashMap compute() and computeIfPresent()

ConcurrentHashMap 的实现非常复杂,因为它专门设计用于允许并发可读性,同时最大限度地减少更新争用。在非常高的抽象层次上,它被组织为一个分桶哈希 table.

在移动应用程序的上下文中,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
        }

在上面的示例中,我正在更新 scheduledTasks,它是一个 ConcurrentHashMap。可以创建跨多个线程的多个计划任务。

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
        }

我只会给出 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;
 }

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