JUC学习之Semaphore

在并发编程网上看到的一个文章,是用Semaphore做流控的例子,其中有个小问题,就是用线程控制许可释放的地方,这里做了个小调整,见代码注释

package semaphore;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 使用Semaphore做流控 每秒只允许某个调用者调用N次
 * 原实现有个问题:
 * 这个代码中,如果有一秒的请求很少或请求数根本就是0,
 * 那么下一秒的许可就可能因为定时release导致许可超过MAX_QPS个,
 * 下一秒的请求数就可以超过MAX_QPS次
 * 修改为,获取当前剩余许可,全部释放
 * */
public class CallController {
    final static int MAX_QPS = 10;
    //这只是初始的一个许可,并没有说是最大限,不断的release,就可以不断的累积许可
    final static Semaphore semaphore = new Semaphore(MAX_QPS);
    
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        //启动一个每500ms运行的线程池,用于重置许可
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){
            @Override
            public void run() {
                //每500ms释放一半,1000ms全部释放
                //semaphore.release(MAX_QPS/2);
                //获取当前可用许可数
                int available = semaphore.availablePermits();
                //只释放用掉的许可证数量
                semaphore.release(MAX_QPS-available);
            }
        }, 1000, 1000, TimeUnit.MILLISECONDS);
        //模拟客户端多线程并发:100线程 * 每个1000次并发调用
        ExecutorService pool = Executors.newFixedThreadPool(100);
        for(int i=1;i<=100;i++){
            final int x = i;
            pool.submit(new Runnable(){
                @Override
                public void run() {
                    for(int j=1;j<=1000;j++){
                        //从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
                        semaphore.acquireUninterruptibly(1);
                        remoteCall(x, j);
                    }
                    
                }
            });
        }
        pool.shutdown();
        //阻塞1小时,直到线程池任务做完
        pool.awaitTermination(1, TimeUnit.HOURS);
        System.out.println("完成");
    }

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

}


你可能感兴趣的:(java,Semaphore,juc)