多线程(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标准库中的并发工具,因为它们经过了更广泛的测试并且优化得更好。

相关推荐
Moment8 分钟前
Node.js v25.0.0 发布——性能、Web 标准与安全性全面升级 🚀🚀🚀
前端·javascript·后端
IT_陈寒23 分钟前
Vite 3.0 性能优化实战:5个技巧让你的构建速度提升200% 🚀
前端·人工智能·后端
程序新视界42 分钟前
MySQL的整体架构及功能详解
数据库·后端·mysql
绝无仅有43 分钟前
猿辅导Java面试真实经历与深度总结(二)
后端·面试·github
绝无仅有1 小时前
猿辅导Java面试真实经历与深度总结(一)
后端·面试·github
Victor3562 小时前
Redis(76)Redis作为缓存的常见使用场景有哪些?
后端
Victor3562 小时前
Redis(77)Redis缓存的优点和缺点是什么?
后端
摇滚侠5 小时前
Spring Boot 3零基础教程,WEB 开发 静态资源默认配置 笔记27
spring boot·笔记·后端
天若有情6737 小时前
Java Swing 实战:从零打造经典黄金矿工游戏
java·后端·游戏·黄金矿工·swin
一只叫煤球的猫8 小时前
建了索引还是慢?索引失效原因有哪些?这10个坑你踩了几个
后端·mysql·性能优化