You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何ForkJoinPool.WorkQueue的push方法需用Unsafe.putOrderedObject而非直接赋值array[index]

Why use Unsafe.putOrderedObject instead of direct array assignment in ForkJoinPool.WorkQueue.push()?

Great question—this is a classic example of balancing concurrency correctness and performance in Java's core libraries. Let's walk through the reasoning behind using Unsafe.putOrderedObject here, using the provided code as context:

final void push(ForkJoinTask<?> task) {
    ForkJoinTask<?>[] a; ForkJoinPool p;
    int b = base, s = top, n;
    if ((a = array) != null) { // ignore if queue removed
        int m = a.length - 1; // fenced write for task visibility
        U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
        U.putOrderedInt(this, QTOP, s + 1);
        if ((n = s - b) <= 1) {
            if ((p = pool) != null)
                p.signalWork(p.workQueues, this);
        } else if (n >= m)
            growArray();
    }
}

Key Reasons for Using Unsafe.putOrderedObject

  • Guaranteeing Cross-Thread Memory Visibility
    A plain array[index] = task assignment doesn't enforce any memory visibility rules across threads. When one thread adds a task to the queue, other worker threads might still see stale, cached versions of the array (thanks to CPU cache hierarchies) and miss the new task entirely. putOrderedObject acts as a store-release operation: it ensures that the write to the array is flushed to main memory, making it visible to other threads eventually. This is non-negotiable for ForkJoinPool, where workers need to reliably pick up new tasks as they're submitted.

  • Balancing Performance vs. Strict Memory Barriers
    You might wonder why not just use a volatile array instead? While volatile does provide visibility, it comes with stricter ordering constraints that add unnecessary overhead. putOrderedObject skips enforcing ordering for subsequent memory operations relative to this write, but still guarantees visibility. For ForkJoinPool—which is optimized for high throughput in parallel tasks—this lighter-weight operation keeps things fast while maintaining correctness.

  • Consistent Memory Semantics for Queue State
    Notice the code also uses U.putOrderedInt to update the top index of the queue. Using putOrdered for both the task assignment and index update ensures that these two operations have matching memory visibility guarantees. If we mixed a plain array assignment with putOrderedInt, we could end up with a race condition where the updated top index is visible to workers before the actual task is in the array—leading to attempts to access a null or uninitialized task.

Wrapping Up

In short, Unsafe.putOrderedObject is the sweet spot here: it gives us the cross-thread visibility we need for concurrent task submission, without the performance cost of stronger memory barriers that aren't required for this specific use case. This aligns perfectly with ForkJoinPool's design goal of efficient parallel task execution.

内容的提问来源于stack exchange,提问作者footmanff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:45:52