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

JVM中Condition与LockSupport哪个性能更优?实验存疑求解

Condition与LockSupport性能对比实验分析

我们开展了同步调用的实验:每个线程任务等待返回自身值+1的任务回调,以此对比Condition与LockSupport的性能差异。实验结果出乎意料:二者总耗时相同,但火焰图差异极大,这是否意味着JVM未对LockSupport进行优化?

火焰图对比

实验代码

public class LockerTest {

    static int max = 100000;
    static boolean usePark = true;

    static Map<Long, Long> msg = new ConcurrentHashMap<>();
    static ExecutorService producer = Executors.newFixedThreadPool(4);
    static ExecutorService consumer = Executors.newFixedThreadPool(16);
    static AtomicLong record = new AtomicLong(0);
    static CountDownLatch latch = new CountDownLatch(max);

    static ReentrantLock lock = new ReentrantLock();
    static Condition cond = lock.newCondition();

    static Map<Long, Thread> parkMap = new ConcurrentHashMap<>();

    static AtomicLong cN = new AtomicLong(0);

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        for (int num = 0; num < max; num++) {
            consumer.execute(() -> {
                long id = record.incrementAndGet();
                msg.put(id, -1L);
                call(id);

                if (usePark) {
                    Thread thread = Thread.currentThread();
                    parkMap.put(id, thread);
                    while (msg.get(id) == -1) {
                        cN.incrementAndGet();
                        LockSupport.park(thread);
                    }
                } else {
                    lock.lock();
                    try {
                        while (msg.get(id) == -1) {
                            cN.incrementAndGet();
                            cond.await();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
                latch.countDown();
            });
        }

        latch.await();
        consumer.shutdown();
        producer.shutdown();

        System.out.printf("park %s suc %s cost %s cn %s"
                , usePark
                , msg.entrySet().stream().noneMatch(entry -> entry.getKey() + 1 != entry.getValue())
                , System.currentTimeMillis() - start
                , cN.get()
        );
    }

    private static void call(long id) {
        producer.execute(() -> {
            try {
                Thread.sleep((id * 13) % 100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (usePark) {
                msg.put(id, id + 1);
                LockSupport.unpark(parkMap.remove(id));
            } else {
                lock.lock();
                try {
                    msg.put(id, id + 1);
                    cond.signalAll();
                } finally {
                    lock.unlock();
                }
            }
        });
    }
}

结果分析

1. 总耗时相同的原因

实验的核心瓶颈不在等待机制,而在producer线程池的处理能力:

  • producer仅配置4个线程,每个任务都包含Thread.sleep((id * 13) % 100)的随机延迟,这部分耗时占据了总运行时间的绝大部分。
  • 不管用Condition还是LockSupport,等待逻辑都是在等待producer完成计算并更新msg,而producer的处理速度直接决定了整体耗时,因此两种方式的总耗时差异不大。

2. 火焰图差异大的原因

两种等待方式的上层逻辑差异导致了火焰图的不同:

  • LockSupport版本:采用精准唤醒,每个线程仅在自己的任务完成后被单独unpark,等待逻辑仅涉及线程状态的直接切换,栈帧更简洁。
  • Condition版本:每次更新msg后调用signalAll,会唤醒所有等待在该Condition上的线程;被唤醒的线程需要重新竞争锁、检查msg状态,大部分线程会再次进入await,这涉及到锁队列、条件队列的维护操作,栈帧中会包含更多与锁调度相关的逻辑。

3. JVM对LockSupport的优化情况

JVM完全对LockSupport做了深度优化:

  • LockSupport的park/unpark是JUC同步框架(如AQS、ReentrantLock)的底层基础,是native方法,直接与操作系统的线程调度机制交互,能高效实现线程的挂起与唤醒。
  • 实际上,Condition的await方法最终也是通过LockSupport实现的,只是Condition额外封装了锁竞争、条件队列管理的逻辑,这才是两者火焰图差异的根源,而非JVM未优化LockSupport。

实验优化建议

如果要更精准对比两种等待方式的性能,建议移除Thread.sleep逻辑,让瓶颈集中在等待与唤醒的调度上,此时LockSupport的精准唤醒优势会更明显,总耗时会低于使用signalAll的Condition版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 04:20:33