基于Semaphore实现Limiter限流器

简介


Semaphore 信号量是用来限制多个线程访问同一个资源,简单来说就是只能有特定数量的线程同时访问资源。与锁不同的是,锁只允许一个线程访问特定的资源,而信号量是允许指定数量的线程同时访问,可以用来协调多线程。

Semaphore 并不是Java语言所特有的,几乎所有的并发语言都有。信号量模型都是一样的,如下:

信号量模型
由计数器、队列和三个方法所组成。

计数器 :记录还可以有多少个线程来访问资源
等待队列 :将等待资源的线程放入此队列

/**
     * Acquires a permit from this semaphore, blocking until one is
     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
     * 阻塞到获取许可
     * <p>Acquires a permit, if one is available and returns immediately,
     * reducing the number of available permits by one.
     * 获取许可,如果有一个许可是可用的,立即返回并减少数量
     * <p>If no permit is available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until
     * one of two things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #release} method for this
     * semaphore and the current thread is next to be assigned a permit; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread.
     * </ul>
     * 如果没有许可可用,那么当前线程就会不可线程调度并且休眠,直到:
     * 1、其他线程调用了release方法释放了该信号量的许可证,并且当前线程是下一个被分配到许可证的
     * 2、其他线程中断了当前线程
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * for a permit,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * @throws InterruptedException if the current thread is interrupted
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

Limiter


基于 Semaphore 可以很轻松的实现限流,比如同一时间内只能有 5 个线程执行:

private static final int THREAD_COUNT = 100;
    private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore semp = new Semaphore(5);
    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
        	semp.acquire();
            executorService.execute(()->{
                try {
                	// 如果无法获取许可,将会一直阻塞...
                    
                    System.out.println("Thread - " + Thread.currentThread().getName() +" sleep ...");
                    Thread.sleep(1000);
                    semp.release();
                } catch (InterruptedException e) {
                	// 如果被中断,则会抛出异常
                    e.printStackTrace();
                }finally {

                }
            });
        }
    }

也可以基于 Semaphore 对特定的特定的资源进行限流。

public class Limiter {


    private Semaphore semaphore = new Semaphore(50);

    private Lock lock = new ReentrantLock();

    public boolean acquire() {
        //lock.lock();
        try {
            // acquire会阻塞
            semaphore.acquire();
            return true;
        } catch (InterruptedException e) {
            // 当前线程被中断时会抛出 InterruptedException
            // Ingore it
            //e.printStackTrace();
            return false;
        } finally {
            //lock.unlock();
        }
    }

    public void release() {
        semaphore.release();
    }

    public static void main(String[] args) {
        Limiter limiter = new Limiter();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                try {
                    if (limiter.acquire()) {
                        System.out.println("sleep------>" + Thread.currentThread().getName());
                        Thread.sleep(10000);
                        System.out.println("wake------>" + Thread.currentThread().getName());
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    limiter.release();
                }
            }, "Thread-" + i).start();

        }
    }

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值