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

Java多线程面试题:限制方法同时访问的线程数上限

实现限流器:控制最多n个线程同时访问

针对你遇到的这个面试问题,我先分享下我当时给出的手动实现方案,再聊聊更优雅的优化思路:

问题回顾

实现一个工具方法,同一时间最多允许n个线程访问;若第n+1个线程发起请求,需等待至已有线程完成。

手动实现的解决方案

我当时写的代码大概是这样的(补全了截断的部分):

class MyMathUtil implements Runnable {
    double a;
    double b;
    Thread t;
    // 静态变量记录当前并发数和最大允许数
    static int currentCount = 0;
    static int maxCount = 2;

    MyMathUtil(double v1, double v2) {
        a = v1;
        b = v2;
        t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {
        try {
            // 进入临界区,判断是否达到并发上限
            synchronized (MyMathUtil.class) {
                // 用while循环防止虚假唤醒
                while (currentCount >= maxCount) {
                    MyMathUtil.class.wait();
                }
                currentCount++;
            }

            // 模拟实际业务操作:比如两数相加
            System.out.println(Thread.currentThread().getName() + " 开始执行计算:" + a + " + " + b);
            Thread.sleep(2000); // 模拟耗时操作
            double result = a + b;
            System.out.println(Thread.currentThread().getName() + " 计算完成,结果:" + result);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        } finally {
            // 执行完成后释放并发名额,唤醒等待的线程
            synchronized (MyMathUtil.class) {
                currentCount--;
                MyMathUtil.class.notifyAll();
            }
        }
    }

    // 测试入口
    public static void main(String[] args) {
        // 启动5个线程,验证最多2个同时执行
        for (int i = 0; i < 5; i++) {
            new MyMathUtil(i, i+1);
        }
    }
}

实现逻辑说明

  • 用静态变量currentCount实时统计当前正在执行的线程数,maxCount设定最大并发阈值
  • 通过synchronized锁定类对象,保证计数操作的线程安全性
  • 进入业务逻辑前,用while循环(必须用while,不能用if,防止虚假唤醒)判断是否达到上限,达到则调用wait()进入等待状态
  • 业务执行完成后,在finally块中减少计数,并调用notifyAll()唤醒所有等待的线程,让它们竞争获取执行权限

更优雅的优化方案:使用JUC的Semaphore

其实Java并发包(java.util.concurrent)里已经提供了现成的工具类Semaphore,可以直接实现这个限流需求,不用手动维护计数和等待唤醒逻辑,代码更简洁可靠:

import java.util.concurrent.Semaphore;

// 业务任务类,和限流逻辑解耦
class MathCalculationTask implements Runnable {
    private final double num1;
    private final double num2;
    private final Semaphore semaphore;

    public MathCalculationTask(double num1, double num2, Semaphore semaphore) {
        this.num1 = num1;
        this.num2 = num2;
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            // 获取许可:如果当前许可数为0,则线程阻塞等待
            semaphore.acquire();
            
            // 执行业务逻辑
            System.out.println(Thread.currentThread().getName() + " 开始计算:" + num1 + " + " + num2);
            Thread.sleep(2000);
            double result = num1 + num2;
            System.out.println(Thread.currentThread().getName() + " 计算完成,结果:" + result);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        } finally {
            // 释放许可:将许可数加1,唤醒等待的线程
            semaphore.release();
        }
    }

    public static void main(String[] args) {
        // 设定最大并发数为2
        int maxConcurrentThreads = 2;
        Semaphore semaphore = new Semaphore(maxConcurrentThreads);

        // 启动5个测试线程
        for (int i = 0; i < 5; i++) {
            new Thread(new MathCalculationTask(i, i+1, semaphore)).start();
        }
    }
}

为什么推荐用Semaphore?

  • 线程安全有保障:Semaphore是JDK官方实现的并发工具类,内部已经处理了所有线程安全问题,比手动实现的等待唤醒逻辑更可靠
  • 解耦业务和限流:限流逻辑由Semaphore负责,业务类只需要专注于自己的计算逻辑,代码复用性更强
  • 灵活配置:Semaphore支持公平/非公平模式(构造时传入true开启公平模式),还能动态调整许可数,扩展性更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:48:02