AQS之Semaphore

AQS在功能上有独占控制和共享控制

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源

Semaphore 同一时间最多允许5个线程同时执行acquire方法和release方法之间的代码

Semaphore semaphore = new Semaphore(5);


@Slf4j
public class SemaphoreExample1 {

    private final static int threadCount = 20;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final Semaphore semaphore = new Semaphore(5);

        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;

            exec.execute(() -> {
                try {
                    semaphore.acquire(); // 获取一个许可
                    test(threadNum);
                    semaphore.release(); // 释放一个许可
                } catch (Exception e) {
                    log.error("exception", e);
                }
            });
        }
        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        log.info("{}", threadNum);
        Thread.sleep(1000);
    }
}
00:28:59.911 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 1
00:28:59.916 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 0
00:28:59.916 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 2
00:28:59.916 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 3
00:28:59.916 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 4
00:29:00.922 [pool-1-thread-6] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 5
00:29:00.922 [pool-1-thread-7] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 6
00:29:00.922 [pool-1-thread-8] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 7
00:29:00.925 [pool-1-thread-9] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 8
00:29:00.937 [pool-1-thread-10] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 9
00:29:01.922 [pool-1-thread-12] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 11
00:29:01.922 [pool-1-thread-11] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 10
00:29:01.922 [pool-1-thread-13] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 12
00:29:01.925 [pool-1-thread-14] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 13
00:29:01.937 [pool-1-thread-15] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 14
00:29:02.923 [pool-1-thread-16] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 15
00:29:02.923 [pool-1-thread-17] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 16
00:29:02.923 [pool-1-thread-18] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 17
00:29:02.926 [pool-1-thread-19] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 18
00:29:02.938 [pool-1-thread-20] INFO com.mmall.concurrency.example.aqs.SemaphoreExample1 - 19

由运行结果可以看出
在同一时刻有5个线程执行acquire方法和release方法之间的代码,之后休眠一秒再次执行

表示允许的最高并发线程数量为5

我们还可以设置acquire()一次获取的许可的数量,
例如将信号量设置为10 一个获取许可为3,则一次有10/3=3个线程同时执行

只有许可不为0时,线程才能执行方法,否则会一直阻塞




@Slf4j
public class SemaphoreExample1 {

    private final static int threadCount = 60;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final Semaphore semaphore = new Semaphore(10);




        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;

            exec.execute(() -> {
                try {
                    System.out.println("开始----------------------------" +Thread.currentThread()+ semaphore.availablePermits());
                    semaphore.acquire(3); // 获取一个许可
                    System.out.println("进入之后------------------------ " +Thread.currentThread()+ semaphore.availablePermits());
                    test(threadNum);
                    semaphore.release(3); // 释放一个许可
                    System.out.println("释放之后----------------------------" +Thread.currentThread()+ semaphore.availablePermits());
                } catch (Exception e) {
                    log.error("exception", e);
                }
            });
        }
        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        log.info("{}", threadNum);
        Thread.sleep(100);

    }
}

可以使用

if (semaphore.tryAcquire()) { // 尝试获取一个许可
                        test(threadNum);
                        semaphore.release(); // 释放一个许可
                    }

如果无法获取许可就结束了

tryAcquire还有另外一个重载
在获取许可时进行等待多少秒,如果N秒之后仍无法获取许可则结束

    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
Semaphore是一个信号量,它是基于AbstractQueuedSynchronizer (AQS)实现的。Semaphore的主要功能是控制同时访问某个资源的线程数量。通过Semaphore,我们可以实现对资源的限流,只允许一定数量的线程同时访问该资源。Semaphore中有一个计数器,表示当前可用的许可数。当一个线程请求许可时,如果计数器大于0,则线程可以获得许可并继续执行;如果计数器等于0,则线程被阻塞并放入等待队列中。当一个线程释放了许可时,计数器会增加,并通知等待队列中的一个线程可以继续执行。 AQS是一个抽象的队列同步器,它是Semaphore的实现基础。AQS中包含了一个双向链表,用于存储等待许可的线程。在获取许可时,线程会尝试获取许可,如果成功则可以继续执行,否则线程会被阻塞并加入等待队列中。在释放许可时,线程会释放持有的许可,并通知等待队列中的一个线程可以继续执行。 通过SemaphoreAQS,我们可以实现对资源的限流和线程的同步控制。Semaphore提供了acquire()方法用于获取许可,release()方法用于释放许可。在获取连接的时候,通过调用Semaphore的acquire()方法可以限制最多只能有一定数量的线程同时获取连接。在归还连接的时候,通过调用Semaphore的release()方法可以释放许可,使得等待队列中的线程可以获取连接继续执行。 综上所述,SemaphoreAQS是实现线程同步和资源限流的重要工具。Semaphore通过AQS实现了对资源的访问控制,通过acquire()和release()方法实现了线程的阻塞和释放。这样可以确保在并发环境下,多个线程对共享资源的访问是有序和安全的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值