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

多线程同步异常:基于Semaphore的rendezvous实现偶现阻塞

问题分析与修复方案

你的代码出现卡住的核心原因有两个:

1. 变量可见性问题

counter变量没有被volatile修饰,线程对它的修改无法及时同步到其他线程的工作内存中。部分线程会一直读取到旧的counter值,卡在while (counter < n)的忙死循环里,永远无法进入后续的临界区代码。

2. 忙等逻辑的不合理性

即使解决了可见性问题,忙等会持续占用CPU资源,这不是线程同步的优雅实现方式,应该用信号量来实现线程的阻塞与唤醒。

修复后的代码

import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;

class Main {
    
    private static final int n = 10;
    // 用volatile保证counter的可见性
    private static volatile int counter = 0;
    private static final Semaphore mutex = new Semaphore(1);
    // 用于阻塞线程,直到所有线程到达会合点
    private static final Semaphore barrier = new Semaphore(0);

    private static class Runner implements Runnable {
        
        @Override
        public void run() {
            try {
                System.out.println("Rendezvous");
                mutex.acquire();
                counter++;
                // 最后一个到达的线程释放n个许可,让所有线程通过
                if (counter == n) {
                    barrier.release(n);
                }
                mutex.release();
                // 等待所有线程到达后再继续
                barrier.acquire();
                System.out.println("Critical Section");
            } catch (InterruptedException ex) {
                System.out.println("线程执行异常: " + ex.getMessage());
            }
        }
    }
    
    public static void main(String[] args) {
        List<Thread> threads = new ArrayList<>();
        for (int i = 0;i < n;i++) {
            Thread t = new Thread(new Runner());
            t.start();
            threads.add(t);
        }
        
        for (Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException ex) {
                System.out.println("等待线程结束异常: " + ex.getMessage());
            }
        }
        
        System.out.println("Completed");
    }
}

修复说明

  • 给counter添加volatile修饰符,确保所有线程能及时看到counter的最新值。
  • 去掉低效的忙等循环,改用barrier信号量实现阻塞:最后一个到达会合点的线程一次性释放n个许可,让所有等待的线程同时通过屏障,进入临界区。
  • 简化信号量的使用逻辑,避免不必要的release和acquire重复调用,减少出错概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:54:55