Java并发编程之Semaphore

标题链接
CountDownLatchJava并发编程之CountDownLatch.

一、概念

Semaphore令牌。是synchronized的加强版,作用是控制线程的并发数量。
Semaphore是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程通过调用acquire()来获取令牌/执行许可。当信号量中还有剩余可使用的令牌时,线程就能获取并且执行完毕后归还。信号量中没有可用令牌,线程必须等待,直到有别的线程释放(归还)令牌为止,线程可以通过release()来释放令牌。
Hystrix中使用Semaphore进行控制并发数量

二、示例

/**
 * @author chengyanqi
 * @date 2020/7/19 17:49
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "拿到了令牌,执行中..." + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
                    Thread.sleep(1000);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "Thread" + i).start();
        }
    }
}
Thread0拿到了令牌,执行中...2020-07-19 05:52:43
Thread2拿到了令牌,执行中...2020-07-19 05:52:43
Thread1拿到了令牌,执行中...2020-07-19 05:52:43
Thread4拿到了令牌,执行中...2020-07-19 05:52:44
Thread5拿到了令牌,执行中...2020-07-19 05:52:44
Thread3拿到了令牌,执行中...2020-07-19 05:52:44
Thread6拿到了令牌,执行中...2020-07-19 05:52:45
Thread7拿到了令牌,执行中...2020-07-19 05:52:45
Thread8拿到了令牌,执行中...2020-07-19 05:52:45
Thread9拿到了令牌,执行中...2020-07-19 05:52:46

//可以看出,规定了三个令牌
//强到令牌的线程可以执行
//没抢到的必须等待其他线程释放

三、说明

  • Semaphore声明
    Semaphore的构造函数接受int型的参数,表示声明的令牌数量,如果在同一时刻允许n个线程获取令牌执行,就传入n
  • 线程调用semaphore的acquire方法获取令牌,进而执行线程。简单理解为获取锁资源,如果获取不到线程就阻塞
  • 线程执行完毕后调用release释放归还令牌。

acquire(int permits):动态添加permits许可数量,表示每次线程占用permits个令牌。
release(int permits):表示释放permits个令牌。

  • 当获取令牌数量大于释放令牌时,执行到令牌分发完毕,后续所有线程均会阻塞。
  • 当获取令牌数量小于释放令牌时,执行过程中会动态扩容semaphore。如new Sempljore(4)初始化四个令牌,acquire(1)每次拿一个,release(2)每次释放两个。那么第二轮占用时,会有8个线程执行。第三次16个

四、其他常用方法

availablePermits():返回Semaphore中当前可以使用的令牌数。
drainPermits():获取所有当前可用的所有许可令牌,并将令牌池中的令牌置0 。
hasQueuedThreads():判断有没有线程在等待/阻塞
getQueueLength()/hasQueuedThreads():判断在当前有没有等待许可的线程信息使用。
tryAcquire(int permits):尝试获取令牌,boolean类型的值。true表示获取到,false表示没有获取到。不传入参数默认为1
tryAcquire(int permits,long timeout,TimeUint unit):获取permits个令牌,在指定时间timout内尝试,unit是timeout的参数。


/**
 * @author chengyanqi
 * @date 2020/7/19 17:49
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2,true);
        for (int i = 0; i < 5; i++) {

            new Thread(() -> {
                try {
                    if (semaphore.tryAcquire(1)) {
                        System.out.println(Thread.currentThread().getName() + "拿到了令牌,执行中..." + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
                        Thread.sleep(1000);
                        semaphore.release(1);
                    } else {
                        System.out.println(Thread.currentThread().getName() + "没有获取到令牌");
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "Thread" + i).start();
        }
    }
}
Thread2没有获取到令牌
Thread4没有获取到令牌
Thread3没有获取到令牌
Thread1拿到了令牌,执行中...2020-07-19 06:27:17
Thread0拿到了令牌,执行中...2020-07-19 06:27:17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程大帅气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值