首页 > 其他分享 >信号量 Semaphore

信号量 Semaphore

时间:2024-09-09 15:15:05浏览次数:5  
标签:许可 int Semaphore 信号量 线程 semaphore final

Semaphore

Semaphore 更加适合用于控制对有限资源的访问,特别是当你需要允许一定数量的线程同时访问资源时

CountDownLatch 更加适合用于协调多个线程的完成状态,确保在某些操作完成后再执行后续操作

它用于控制对共享资源的访问,通过维护一个许可的计数器来限制同时访问某个资源的线程数量,常用方法如下

Semaphore semaphore = new Semaphore(3); // 允许最多3个线程同时访问资源
semaphore.acquire(); // 线程在访问共享资源之前需要调用 acquire() 方法来获取许可。如果没有可用的许可,线程将会被阻塞,直到有许可可用。
semaphore.release(); // 线程在完成对共享资源的访问后,需要调用 release() 方法来释放许可。释放许可后,其他被阻塞的线程可以获得许可并继续执行
semaphore.tryAcquire(); // 用于尝试获取许可但不会阻塞。如果无法立即获取许可,该方法将返回 false
semaphore.acquire(2); // 获取2个许可
semaphore.release(2); // 释放2个许可

用法示例

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final int MAX_PERMITS = 3; // 许可总数
    private static final Semaphore semaphore = new Semaphore(MAX_PERMITS); // 创建一个信号量(持有3个许可)

    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                System.out.println(Thread.currentThread().getName() + " 尝试获取许可");
                semaphore.acquire(); // 获取许可(每获取一个池子中的许可就少一个)
                System.out.println(Thread.currentThread().getName() + " 得到许可");

                Thread.sleep(2000);

                System.out.println(Thread.currentThread().getName() + " 释放许可");
                semaphore.release(); // 释放许可(释放的许可会回到信号量池子中)
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        };

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

原理

  • 创建 Semaphore 实例

    同 ReentrantLcok,默认创建非公平锁,也可以带参数指定公平还是非公平,正数的参数会设置给 AQS 的 state 变量

    // 构造方法
    public Semaphore(int permits) {
        // 创建了一个非公平锁
        sync = new NonfairSync(permits);
    }
    
    // 非公平锁,继承 Sync,和前面的锁一样,这个 Sync 也是继承 AQS 
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;
    
        NonfairSync(int permits) {
            // 调用父类构造方法,也就是 Sync
            super(permits);
        }
    
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }
    
    // Sync 构造方法
    Sync(int permits) {
        // 这个方法是 AQS 的
        setState(permits);
    }
    
    // java.util.concurrent.locks.AbstractQueuedSynchronizer#setState
    protected final void setState(int newState) {
        // 设置 state 变量
        state = newState;
    }
    
  • 获取许可

    // java.util.concurrent.Semaphore#acquire()
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    // java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireSharedInterruptibly
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        // 获取许可,模板方法,当小于 0,就说明当前没有许可了,返回值大于0,什么都不做,表示获取锁成功(内部已经 cas 维护了 state)
        if (tryAcquireShared(arg) < 0) 
            doAcquireSharedInterruptibly(arg); // 如果许可不足,走这里
    }
    
    // java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquireShared
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // java.util.concurrent.Semaphore.NonfairSync#tryAcquireShared
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
    
    // java.util.concurrent.Semaphore.Sync#nonfairTryAcquireShared
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            int available = getState(); // 拿到 state(如果是 2 表示已经颁发了 2 个许可了)
            int remaining = available - acquires; // 计算剩余许可,可能小于 0,表示没有许可了,可能大于 0,表示许可够
            if (remaining < 0 ||
                compareAndSetState(available, remaining)) // 如果 remaining 不小于 0,说明许可是够的,cas 设置 state(当前剩余许可设置到 state)
                return remaining; // 返回 remaining
        }
    }
    
    // java.util.concurrent.locks.AbstractQueuedSynchronizer#doAcquireSharedInterruptibly
    private void doAcquireSharedInterruptibly(int arg) // 这个现在太熟悉了,看过太多次了,线程入队,维护节点,挂起线程
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    

标签:许可,int,Semaphore,信号量,线程,semaphore,final
From: https://www.cnblogs.com/cyrushuang/p/18404625

相关文章

  • freeRTOS面试题目 面经 单片机面经汇总MCU RTOS常见面试经验汇总 freeRTOS消息队列 信
    常见rtos部分Linux题目汇总FreeRtos面经30题前后台程序与实时操作系统的区别是什么?实时系统的基本特性有哪些?什么是不可剥夺型内核?它的特点是什么?可剥夺型内核的定义及适用场景是什么?什么是可重入型函数?它有什么特点?使用可剥夺型内核时,为什么不应直接使用不可重入型函数......
  • php Semaphore 函数 信号量
    1一些理论基础:信号量:又称为信号灯、旗语用来解决进程(线程同步的问题),类似于一把锁,访问前获取锁(获取不到则等待),访问后释放锁。临界资源:每次仅允许一个进程访问的资源。临界区:每个进程中访问临界资源的那段代码叫临界区进程互斥:两个或以上的进程不能同时进入关于同一组共享变量......
  • linux进程间通信——信号量(通俗易懂,看这一篇就够了)
    信号量概念特点信号量实际是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。很多进程会访问同一资源,或者向共享内存写入一些东西,为防止争夺资源混乱。可以给一些进程上锁,让其排队等待工作原理P(sv):如果sv的值大于零,就给它减1;如果它的值为......
  • SolidJS-多文件间传递同一个信号量
    SolidJS-多文件间传递同一个信号量现在我在controlPanel.tsx中返回了一个控制面板(HTML代码),可以控制node、link、step1和step2的值。在matrixWave.tsx中我根据node、link、step1和step2的值进行数据的过滤,然后生成对应的matrixWave的SVG图。因此,我希望在web中对node、link、step1......
  • [Java并发]Semaphore
    Semaphore是一种同步辅助工具,翻译过来就是信号量,用来实现流量控制,它可以控制同一时间内对资源的访问次数.无论是Synchroniezd还是ReentrantLock,一次都只允许一个线程访问一个资源,但是Semaphore可以指定多个线程同时访问某一个资源.Semaphore有一个构造函数,可以传入一个int型......
  • 基于STM32F103的FreeRTOS系列(十一)·信号量·二值信号量与计数信号量详细使用以及移植
    目录1. 信号量简介1.1 同步和互斥1.1.1 同步1.1.2 互斥1.1.3 总结1.2 分类1.2.1 二值信号量1.2.2 计数信号量1.2.3 互斥信号量1.2.4 递归信号量2. 信号量控制块3. 常用信号量API函数3.1 创建信号量函数3.1.1 创建二值信号量 xSe......
  • FreeRTOS 快速入门(五)之信号量
    目录一、信号量的特性1、信号量跟队列的对比2、两种信号量的对比二、信号量1、二值信号量1.1二值信号量用于同步1.2二值信号量用于互斥2、计数信号量三、信号量函数1、创建2、删除3、give/take一、信号量的特性信号量(Semaphore)是一种实现任务间通信的机制,可以......
  • 信号量、PV操作及软考高级试题解析
    信号量在并发系统中,信号量是用于控制公共资源访问权限的变量。信号量用于解决临界区问题,使得多任务环境下,进程能同步运行。此概念是由荷兰计算机科学家Dijkstra在1962年左右提出的。信号量仅仅跟踪还剩多少资源可用,不会跟踪哪些资源是可用的。信号量机制,处理进程同步和互斥的问......
  • 嵌入式学习---DAY27:信号量、进程间的通信
    一、信号量信号量(semaphore)是操作系统用来解决并发中的互斥和同步问题的一种方法。信号量(个数)---反映的是资源的数量信号量的分类:信号无名量==》线程间通信             有名信号量==》进程间通信1.信号量的定义(为全局变量)sem_t sem......
  • 信号量机制以及管道通信
    一、信号量(个数)反映的是资源的数量1.1、信号量定义1、信号量-----来描述可使用的资源的个数2、p操作-----表示使用这个资源资源个数减一1.2、p操作逻辑尝试获取资源有资源可用,直接使用,资源个数减一如果没有资源则等待v操作------产生这个资源资源个数加11.3、......