Java并发编程:AbstractQueuedSynchronizer之Semaphore源码分析1.8

本文详细解析了Semaphore的工作原理,包括其内部类、非公平锁与公平锁的实现,以及如何使用Semaphore来限制线程访问共享资源的数量,进行流量控制。通过实例代码展示了Semaphore在并发控制中的应用。
摘要由CSDN通过智能技术生成

一、Semaphore
Semaphore管理的是一组许可证,acquire方法将获取一个许可证,如果池中还有许可证,则获取成功并持有该许可证,否则阻塞。release方法向池中添加一个许可证,释放成功,acquire方法阻塞的线程就会唤醒并获得许可证。实际上许可证并不特指某些对象,而是由一个整形数字扮演许可证的角色。

内部类:
1、sync:队列

abstract static class Sync extends AbstractQueuedSynchronizer {

继承AQS,构建等待队列

2、nonfairSync:非公平锁

static final class NonfairSync extends Sync {

3、FairSync:公平锁

static final class FairSync extends Sync {

二、应用
常用来限制线程访问共享资源的数量,做流量分流。

实例代码:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
 
public class SemaphoreExample {
 
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(8);
        final Semaphore semaphore = new Semaphore(5);
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 1; i <= 8; i++) {
            final int index = i;
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println("当前线程:" + Thread.currentThread().getName() + " 获得许可" );
                        //不释放锁,模拟业务操作
                        Thread.sleep(1000);
                        System.out.println("当前线程:" + Thread.currentThread().getName() + "释放许可");
                        //System.out.println("当前允许进入的最大任务数:" + semaphore.availablePermits());
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally{
                        if(index == 8){
                            countDownLatch.countDown();
                        }
                    }
 
                }
            });
        }
        try {
            System.out.println("main线程等待:" + Thread.currentThread().getName());
            countDownLatch.await();
            System.out.println("模拟执行完毕.....");
            System.out.println("关闭线程池");
            service.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果:

 
当前线程:pool-1-thread-1 获得许可
当前线程:pool-1-thread-4 获得许可
当前线程:pool-1-thread-3 获得许可
当前线程:pool-1-thread-5 获得许可
当前线程:pool-1-thread-2 获得许可
main线程等待:main
当前线程:pool-1-thread-1释放许可
当前线程:pool-1-thread-2释放许可
当前线程:pool-1-thread-3释放许可
当前线程:pool-1-thread-6 获得许可
当前线程:pool-1-thread-7 获得许可
当前线程:pool-1-thread-8 获得许可
当前线程:pool-1-thread-4释放许可
当前线程:pool-1-thread-5释放许可
当前线程:pool-1-thread-6释放许可
当前线程:pool-1-thread-8释放许可
模拟执行完毕.....
关闭线程池
当前线程:pool-1-thread-7释放许可

许可就等待,否则执行任务处理。

三、实现原理

1、acquire实现:

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

acquires值默认为1,表示尝试获取1个许可,remaining代表剩余的许可数。

  • 如果remaining < 0,表示目前没有剩余的许可。
  • 当前线程进入AQS中的doAcquireSharedInterruptibly方法等待可用许可并挂起,直到被唤醒。

2、 release实现

protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        int current = getState();
        int next = current + releases;
        if (next < current) // overflow
            throw new Error("Maximum permit count exceeded");
        if (compareAndSetState(current, next))
            return true;
    }
}

releases值默认为1,表示尝试释放1个许可,next 代表如果许可释放成功,可用许可的数量。

  • 通过unsafe.compareAndSwapInt修改state的值,确保同一时刻只有一个线程可以释放成功。
  • 许可释放成功,当前线程进入到AQS的doReleaseShared方法,唤醒队列中等待许可的线程。

3、公平acquire实现:

protected int tryAcquireShared(int acquires) {
    for (;;) {
        if (hasQueuedPredecessors())
            return -1;
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

acquires值默认为1,表示尝试获取1个许可,remaining代表剩余的许可数。
可以看到和非公平策略相比,就多了一个对阻塞队列的检查。

  • 如果阻塞队列没有等待的线程,则参与许可的竞争。
  • 否则直接插入到阻塞队列尾节点并挂起,等待被唤醒。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值