并发控制利器Semaphore

简介: 并发控制利器Semaphore

并发控制利器:Semaphore详解与应用

简介

Semaphore 是Java并发编程中的一个重要工具,用于管理对共享资源的访问权限,确保系统资源不会因过度访问而耗尽。形象地说,Semaphore 可以比喻为交通信号灯,它控制着能够同时进入特定区域(如马路)的车辆数(线程数)。当一定数量的车辆(线程)进入后,其余车辆必须等待,直到有车辆离开,空出“车位”(许可证)为止。在编程中,Semaphore 通过协调线程访问,保证公共资源的合理分配。



应用场景

Semaphore 特别适用于有限资源访问控制的场景,例如数据库连接池管理、文件读写控制等。一个典型示例是数据库连接限制:假设你需要从数万个文件中读取数据,并将其保存至数据库,虽然读取操作(IO密集型)可以并行处理,但数据库连接数有限(例如10个)。此时,Semaphore 可以用来控制仅有10个线程能同时获取数据库连接,避免超出连接池容量。

public class SemaphoreTest {
    private static final int THREAD_COUNT = 30;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10);

    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();
                        System.out.println("Saving data...");
                        s.release();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

在这个例子中,尽管启用了30个线程,但最多只有10个线程能够同时执行数据库保存操作,通过 Semaphore(10) 初始化,确保了并发访问的线程数不超过10。


其他方法及实现机制

Semaphore 提供了多个方法来帮助管理资源访问:

  • availablePermits():返回当前可用的许可证数量。
  • getQueueLength():返回等待获取许可证的线程数。
  • hasQueuedThreads():检查是否有线程正在等待许可证。
  • reducePermits(int reduction):减少指定数量的许可证,是一个受保护方法。
  • getQueuedThreads():返回所有等待的线程集合,同样是受保护方法。

Semaphore 的内部实现基于AQS(AbstractQueuedSynchronizer),利用了CLH队列来管理等待线程。CLH队列是一种FIFO(先进先出)的线程等待队列,当线程尝试获取许可证失败时,会被封装成节点加入到队列中等待。CLH队列的节点结构包含前驱节点和后继节点的引用,以及线程状态等信息,通过这些信息维护线程的等待顺序。


在尝试获取锁的操作中,AQS的acquire() 方法首先尝试快速获取资源,失败则通过addWaiter()方法将当前线程封装成节点并加入队列。此过程体现了CLH队列的结构和等待机制,确保了线程安全且高效地获取和释放资源。


总之,Semaphore 作为一种灵活的并发控制工具,通过限制并发访问的数量,有效管理共享资源,是解决资源竞争和提高系统并发能力的重要手段。

相关文章
|
9月前
|
Java
Java并发编程中的锁机制
【2月更文挑战第22天】 在Java并发编程中,锁机制是一种重要的同步手段,用于保证多个线程在访问共享资源时的安全性。本文将介绍Java锁机制的基本概念、种类以及使用方法,帮助读者深入理解并发编程中的锁机制。
|
9月前
|
缓存 安全 Java
高性能解决线程饥饿的利器 StampedLock
高性能解决线程饥饿的利器 StampedLock
112 1
|
6月前
|
Java 开发者
解锁并发编程新姿势!深度揭秘AQS独占锁&ReentrantLock重入锁奥秘,Condition条件变量让你玩转线程协作,秒变并发大神!
【8月更文挑战第4天】AQS是Java并发编程的核心框架,为锁和同步器提供基础结构。ReentrantLock基于AQS实现可重入互斥锁,比`synchronized`更灵活,支持可中断锁获取及超时控制。通过维护计数器实现锁的重入性。Condition接口允许ReentrantLock创建多个条件变量,支持细粒度线程协作,超越了传统`wait`/`notify`机制,助力开发者构建高效可靠的并发应用。
107 0
|
9月前
并发编程之读写锁ReadWriteLock的详细解析(带小案例)
并发编程之读写锁ReadWriteLock的详细解析(带小案例)
75 0
|
9月前
|
缓存 安全 Java
Java并发编程中的锁机制及其应用
传统的锁机制在Java并发编程中扮演着重要角色,但随着技术的发展,新的锁机制和应用不断涌现。本文将深入探讨Java并发编程中常用的锁机制,包括synchronized关键字、ReentrantLock、ReadWriteLock等,并结合实际案例分析其应用场景和优劣势。通过本文的阐述,读者将对Java并发编程中的锁机制有更为深入的了解。
78 0
|
5月前
|
Java 数据库
JAVA并发编程-一文看懂全部锁机制
曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知! 今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。
|
5月前
|
安全 Java 开发者
Java并发编程中的锁机制解析
本文深入探讨了Java中用于管理多线程同步的关键工具——锁机制。通过分析synchronized关键字和ReentrantLock类等核心概念,揭示了它们在构建线程安全应用中的重要性。同时,文章还讨论了锁机制的高级特性,如公平性、类锁和对象锁的区别,以及锁的优化技术如锁粗化和锁消除。此外,指出了在高并发环境下锁竞争可能导致的问题,并提出了减少锁持有时间和使用无锁编程等策略来优化性能的建议。最后,强调了理解和正确使用Java锁机制对于开发高效、可靠并发应用程序的重要性。
48 3
|
安全 Java 开发者
深入解析ReentrantLock重入锁:Java多线程中的利器
深入解析ReentrantLock重入锁:Java多线程中的利器
1892 4
|
9月前
多线程并发锁的方案—互斥锁
多线程并发锁的方案—互斥锁
|
9月前
多线程并发锁方案—自旋锁
多线程并发锁方案—自旋锁