高通量一个变量写在Java中8并发?

问题描述 投票:3回答:1

如果我有一个Java 8个程序是由多个线程读取和写入的一个简单的整数。

如果我告诉应用程序需要支持高吞吐量读取和很少写 - 这个问题的答案很简单,我只是用一个读写锁。然后,多个线程可以执行与不堵的同时读取 - 只有当阻塞不常写操作完成时发生。

但在情况下,如果有人告诉我的应用程序需要支持高吞吐量写入(即共享变量是由不同的线程频繁更新)。无论我可以看到什么样的锁我在这里使用,尽可能的将总是导致线程阻塞 - 当一个线程获得的变量和更新锁,它的其余线程也试图更新该变量将不得不等待,直到他们得到的锁定 - 这是正确的还是我失去了在Java中8的东西吗?

我可以去,并且写一些排序上的共享变量,其中线程调用它立即返回更新方法的异步更新方法,我使用某种形式的被窝里的数据结构来排队写入共享变量。至少这样我会阻止线程试图更新共享变量时阻塞。诚然这种方法会提高其他问题,如应线程承担其保证写DEF。成功或者我应该提供一个回调,以通知更新是否成功等。除了这样的事情,我看不出有什么办法一轮阻塞在Java中使用8锁定任何高通量写什么时候? (或者我应该接受阻塞,只是,即使在高吞吐量的情况下写使用锁反正)。谢谢

concurrency java-8 locking java.util.concurrent
1个回答
3
投票

严格地说Integer的 - 你可以使用LongAdder,它的实现是完全针对你的情况看来。如果你关心这里有一些额外的细节。

它采用CAS(比较和交换)的引擎盖下,很像AtomicLong,但有一些不同之处。首先,它拥有被包裹在一个所谓的long value实际Cell的 - 基本上是一类允许casvalue(比较和交换),以新的价值,就像一个二传手,如果你想要的。这Cell还标注有@sun.misc.Contended以防止共享的错误;这里是它的解释(从代码中的注释):

但居住在阵列原子对象将倾向于相邻放置对方,等会多数情况下没有这种预防措施共享的高速缓存行(与一个巨大的性能产生负面影响)。

实施是从这里很有趣。让我们来看看,当你调用add(long x)方法会发生什么:

 public void add(long x) {
    Cell[] cs; long b, v; int m; Cell c;
    if ((cs = cells) != null || !casBase(b = base, b + x)) {
        boolean uncontended = true;
        if (cs == null || (m = cs.length - 1) < 0 ||
            (c = cs[getProbe() & m]) == null ||
            !(uncontended = c.cas(v = c.value, v + x)))
            longAccumulate(x, null, uncontended);
    }
}

我们的想法是,如果Cell [] cs为null,之前有没有竞争,这意味着long value或者是未初始化或以前所有CAS操作已经被所有线程成功。在这种情况下,尝试新的价值CASlong value - 是否奏效,我们就完成了。如果,虽然失败了,也创造了Cell []的阵列,使每个单独的线程试图在自己的空间里工作,最大限度地减少争。

下一句是什么,你真正关心的,如果我理解正确你的问题(这是我的,不会从代码中的注释来在所有):

在简单的话:如果线程之间没有竞争,工作仿佛AtomicLong使用(在某种程度上)完成,否则试图创建一个单独的空间,每个线程去努力。

如果你关心一些额外的细节,我发现有趣:

所述Cell[]总是两个(很像HashMap内部阵列)的功率;然后每个线程使用ThreadLocalRandom创造一些的hashCode,试图找到在阵列Cell [] cs条目写,甚至再重新使用散列以Marsaglia XorShif试图找到这个阵列中的空闲插槽;数组的大小上限,以你(最近的两个从实际功率)内核的数量,这个数组可以调整大小,因此它可以成长,所有这些操作都使用volatile int cellsBusy自旋锁完成。此代码是一流的,但正如所说,我没有得到这一切。

© www.soinside.com 2019 - 2024. All rights reserved.