Java里怎样实现课程报名人数限制

来源:网站建设作者:菲律宾程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《Java里怎样实现课程报名人数限制》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java里怎样实现课程报名人数限制》有用,将其分享出去将是对创作者最好的鼓励。

课程报名人数限制是教育培训类系统的常见需求,核心目标是确保报名总人数不超过课程设定的最大容量,同时要处理多用户同时报名的并发场景,避免出现超报问题。下面先介绍基础的实现思路,再逐步优化到适配高并发的方案。

Java里怎样实现课程报名人数限制

基础实现:使用普通计数器

最基础的思路是维护一个当前报名人数的计数器,每次报名时先判断当前人数是否小于最大限制,再执行加一操作。这种方式在单线程场景下可以正常工作,但并发场景下会出现问题。

public class CourseEnroll {
    // 课程最大报名人数
    private int maxCount = 100;
    // 当前报名人数
    private int currentCount = 0;

    public boolean enroll() {
        if (currentCount < maxCount) {
            // 模拟业务处理耗时
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            currentCount++;
            return true;
        }
        return false;
    }

    public int getCurrentCount() {
        return currentCount;
    }
}

并发问题说明

当两个线程同时判断currentCount < maxCount为true时,都会执行后续的加一操作,最终导致报名人数超过最大限制。比如最大限制是100,两个线程同时进入判断后,最终currentCount会变成102,出现超报情况。

方案一:使用synchronized关键字实现同步

synchronized是Java内置的同步机制,可以保证同一时间只有一个线程执行被修饰的代码块,避免并发冲突。我们可以对报名方法进行同步控制。

public class CourseEnrollSync {
    private int maxCount = 100;
    private int currentCount = 0;

    // 同步方法,同一时间只有一个线程可以执行
    public synchronized boolean enroll() {
        if (currentCount < maxCount) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            currentCount++;
            return true;
        }
        return false;
    }

    public int getCurrentCount() {
        return currentCount;
    }
}

这种方式虽然解决了并发问题,但synchronized是重量级锁,高并发场景下性能较差,所有报名请求会排队执行,响应速度会变慢。

方案二:使用AtomicInteger实现原子操作

AtomicInteger是java.util.concurrent.atomic包下的原子类,提供了原子性的自增、判断等操作,性能比synchronized更好,适合高并发场景。

import java.util.concurrent.atomic.AtomicInteger;

public class CourseEnrollAtomic {
    private int maxCount = 100;
    // 原子类型的当前报名人数
    private AtomicInteger currentCount = new AtomicInteger(0);

    public boolean enroll() {
        // 循环尝试报名,直到成功或者人数已满
        while (true) {
            int nowCount = currentCount.get();
            if (nowCount >= maxCount) {
                return false;
            }
            // 原子性地比较并自增,如果当前值还是nowCount,就自增1,返回自增前的值
            if (currentCount.compareAndSet(nowCount, nowCount + 1)) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            }
            // 如果compareAndSet失败,说明有其他线程修改了currentCount,重新循环尝试
        }
    }

    public int getCurrentCount() {
        return currentCount.get();
    }
}

compareAndSet是CAS(比较并交换)操作,是乐观锁的实现,不需要阻塞线程,性能比synchronized更好,适合高并发的报名场景。

方案三:结合数据库实现持久化限制

上面的方案都是内存中的计数器,系统重启后数据会丢失,实际开发中通常需要结合数据库实现持久化的报名限制。我们可以通过数据库的乐观锁或者行锁来控制人数。

数据库表结构示例:

字段名类型说明
idbigint课程ID
course_namevarchar课程名称
max_enrollint最大报名人数
current_enrollint当前报名人数
versionint版本号,用于乐观锁

使用乐观锁的更新SQL示例:

UPDATE course 
SET current_enroll = current_enroll + 1, version = version + 1 
WHERE id = ? 
AND current_enroll < max_enroll 
AND version = ?

Java中执行该SQL后,判断受影响行数,如果大于0说明报名成功,否则说明人数已满或者版本号冲突,需要重试或者返回失败。

不同方案的选择建议

  • 如果是单机、低并发的临时场景,可以使用synchronized或者AtomicInteger的内存计数器方案
  • 如果是分布式系统或者需要持久化报名数据,建议结合数据库的乐观锁方案,同时可以搭配Redis缓存计数器提升性能
  • 高并发场景下优先选择AtomicInteger或者数据库CAS操作,避免使用重量级锁

Java课程报名限制并发控制synchronizedAtomicInteger修改时间:2026-06-28 19:27:41

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。