semaphore学习

1、semaphore概述

semaphore可以看作是一个许可的集合,用于控制多个线程对有限共享资源的访问。当某个线程需要访问资源时,必须首先从semaphore获取一个许可,使用完资源后再将许可归还给semaphore。

2、semaphore常用方法

控制共享资源的多线程访问

(1)初始化许可数量
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

(2)获得许可
available.acquire(); // 从Semaphore获取【一个】许可,成功则立即返回,并将剩余许可数减1,如果没有可用许可则阻塞直至拿到可用许可
available.acquire(int num); // 一次获取【多个】
available.acquireUninterruptibly(); // 与acquire()区别是当线程发生中断后,是否还继续等待获取许可
available.tryAcquire(); // 与acquire()区别是当前没有可用许可时,是否阻塞
available.tryAcquire(timeout, unit); // 不阻塞,在指定时间内没有可用许可则直接返回false

(3)归还许可
available.release(); // 归还【一个】许可给Semaphore,并将许可数加1
available.release(int num); // 归还【多个】

注意:release()释放的许可不一定是acquire()获取的许可

(4)查询可用许可数量
available.availablePermits();

当做互斥锁使用

private final Semaphore available = new Semaphore(1);
当许可只有1个时,可以实现类似synchronized或lock的功能,任何时候只能有一个线程操作共享资源

支持公平与非公平模式

等待时间长的线程是否优先获得许可

3、semaphore应用

控制客户端在单位时间内调用某个远程服务不超过N次

public class TestSemaphore2 {

    final static int MAX_QPS = 10;
    final static Semaphore semaphore = new Semaphore(MAX_QPS);

    public static void main (String ... args) throws Exception {
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                semaphore.release(MAX_QPS-semaphore.availablePermits()); // 防止许可一直递增
                System.out.println("--------------------------");
            }
        }, 5000, 5000, TimeUnit.MILLISECONDS);

        //lots of concurrent calls:100 * 1000
        ExecutorService pool = Executors.newFixedThreadPool(100);
        for (int i=100;i>0;i--) {
            final int x = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j=1000;j>0;j--) {
                        semaphore.acquireUninterruptibly(1);
                        remoteCall(x, j);
                    }
                }
            });
        }

        pool.shutdown();
        pool.awaitTermination(1, TimeUnit.HOURS);
        System.out.println("DONE");
    }

    private static void remoteCall(int i, int j) {
        System.out.println(String.format("%s - %s: %d %d",new Date(),
            Thread.currentThread(), i, j));
    }
}

4、参考
http://ifeve.com/concurrency-practice-1/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值