多线程(69)如何使用synchronized实现信号量

在Java中,信号量(Semaphore)是一种常用的同步工具,它可以用来控制对共享资源的访问数量。信号量主要用于两个目的:一个是用于多个共享资源的互斥使用,另一个是用于并发线程数的控制。虽然Java的java.util.concurrent包提供了Semaphore类,但了解如何手动实现一个信号量可以帮助更深入地理解并发编程的原理。

下面,我们将使用Synchronized关键字来实现一个简单的信号量。我们的目标是实现一个计数信号量,其中信号量的计数指示可以同时访问某一资源的线程数。

实现基本框架

首先,我们定义一个Semaphore类,它需要维护一个计数器来跟踪可用的许可证数量。计数器的初始值在信号量创建时通过构造函数提供。

java 复制代码
public class SimpleSemaphore {
    private int signals = 0;
    private int bound = 0;

    public SimpleSemaphore(int upperBound) {
        this.bound = upperBound;
    }
}

实现acquire方法

acquire方法用于获取一个许可。如果当前没有可用的许可(即signals等于上界bound),那么该方法将阻塞,直到有许可可用。

java 复制代码
public synchronized void acquire() throws InterruptedException {
    while (signals == bound) {
        wait();
    }
    signals++;
    notify();
}

这里使用synchronized关键字来保证方法是线程安全的。如果signals达到bound,调用wait()使当前线程等待,直到signals减少后再继续执行。每次调用acquire方法时,signals都会增加,并且通过notify()唤醒可能在等待的线程。

实现release方法

release方法用于释放一个许可,增加可用许可的数量。如果有线程正在等待许可,那么其中一个线程将被唤醒。

java 复制代码
public synchronized void release() throws InterruptedException {
    while (signals == 0) wait();
    signals--;
    notify();
}

同样,使用synchronized确保线程安全,并在释放许可后通过notify()唤醒可能正在等待的线程。

示例使用

以下是如何使用SimpleSemaphore的一个简单示例。

java 复制代码
public class Main {
    public static void main(String[] args) {
        SimpleSemaphore semaphore = new SimpleSemaphore(3); // 允许3个线程同时访问

        Runnable longRunningTask = () -> {
            try {
                semaphore.acquire();
                System.out.println("Thread " + Thread.currentThread().getId() + " is running");
                // 模拟长时间的任务
                Thread.sleep(2000);
                semaphore.release();
                System.out.println("Thread " + Thread.currentThread().getId() + " is finished");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(longRunningTask).start();
        }
    }
}

在这个示例中,我们创建了一个具有3个许可的SimpleSemaphore,然后启动了10个线程来执行一项长时间运行的任务。由于信号量的限制,这10个线程将分批(每批3个)执行。

总结

通过使用synchronized关键字、wait()和notify()方法,我们可以手动实现一个简单的信号量。这个实现提供了互斥访问和线程间的协调能力。虽然Java的Semaphore类提供了更高级的功能,但手动实现信号量是理解并发控制的一个很好的练习。记住,真实环境下应优先使用Java标准库中的并发工具,因为它们经过了更广泛的测试并且优化得更好。

相关推荐
行百里er8 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机9 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
孟健9 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
码事漫谈10 小时前
丢得静悄悄,谈一谈 Agent 的记忆是怎么没的
后端
迪飞特科技10 小时前
智慧物业平台实战:Spring Boot 整合小程序实现报修巡检费用全流程
spring boot·后端·小程序
考虑考虑10 小时前
@JsonInclude注解使用
spring boot·后端·spring
IT_陈寒11 小时前
Vite的这个问题坑了我三天,原来如此解决!
前端·人工智能·后端
网易云信11 小时前
大模型能上岗做销售吗?我们让 12 款国产模型交了 420 份作业
前端·后端
CCblandy11 小时前
HTTP 长连接 3 类故障实测:[WinError 10053]、99 个 TIME_WAIT、69 次多余握手,4 种对策怎么选
后端·python·网络协议·http·云原生·性能优化·架构
蜗牛互联网11 小时前
Python Agent工具调用的白名单、参数校验与审批门禁
java·服务器·前端·人工智能·后端·python