RateLimiter 的限流操作---漏桶算法的应用

/**

 * @create 2021-02-15 11:35

 * @desc 请求类

 **/
public class Request
{
   private final int data;

   public Request(int data)
   {
      this.data = data;
   }

   public int getData()
   {
      return data;
   }

   @Override
   public String toString()
   {
      return "Request{" + "data=" + data + '}';
   }
}

--------------------

import com.google.common.util.concurrent.Monitor;
import com.google.common.util.concurrent.RateLimiter;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;

import static java.lang.Thread.currentThread;

/**

 * @create 2021-02-15 11:36

 * @desc 漏桶算法的应用

 **/
public class RateLimiterBucket
{
   //漏桶采用线程安全的容器
   private  final ConcurrentLinkedQueue bucket = new ConcurrentLinkedQueue<>();
   //定义漏桶的上沿容量
   private final static int BUCKET_CAPACITY = 10;
   //定义漏桶的下沿水流速率,每秒匀速放行 5 个 Request
   private final RateLimiter rateLimiter = RateLimiter.create(5.0D);
   //提交请求时需要用到的 Monitor
   private final Monitor requestMonitor = new Monitor();
   //处理请求时需要用到的 Monitor
   private final Monitor handleMonitor = new Monitor();

   public void submitRequest(int data)
   {
      this.submitRequest(new Request(data));
   }

   // 该方法主要用于接受来自客户端提交的请求数据
   public void submitRequest(Request request)
   {

      /**
       *  enterIf() 方法: 主要用于判断当前的 Guard 是否满足临界值的判断,
       *                  也是使用比较多的一个操作,调用该方法,当前线程
       *                  并不会进入阻塞之中
       */
      if(requestMonitor.enterIf(new Monitor.Guard(requestMonitor)
       {
          @Override
          public boolean isSatisfied()
          {
             return bucket.size() < BUCKET_CAPACITY;
          }
       }))
      {
         try
         {
            // 向桶中加入新的 request
            boolean result = bucket.offer(request);
            if(result)
            {
               System.out.println(currentThread() + " submit request : " + request.getData()+
               " successfully.");
            }
            else
            {
               // 此处可以将请求数据存入“高吞吐量的 MQ 中”,然后从 MQ 中消费请求,再尝试提交
               System.out.println("produce into MQ and will try again later.");
            }
         }
         finally
         {
            requestMonitor.leave();
         }
      }
      else
      {
         // 当漏桶溢出的时候做“降权”处理
         System.out.println("The request:" + request.getData() + "will be down-dimensional handle"
               + "due to bucket is overflow");
         // 此处可以将请求数据存入“高吞吐量的 MQ 中”,然后从 MQ 中消费请求,再尝试提交
         System.out.println("produce into MQ and will try again later.");
      }
   }

   // 该方法主要从漏桶中匀速地处理相关请求
   public void handleRequest(Consumer consumer)
   {
      // 若漏桶中存在请求,则处理
      if( handleMonitor.enterIf(new Monitor.Guard(handleMonitor)
      {
         @Override
         public boolean isSatisfied()
         {
            return !bucket.isEmpty();
         }
      }))
      {
         try
         {
            // 匀速处理
            rateLimiter.acquire();
            // 处理数据
            consumer.accept(bucket.poll());
         }
         finally
         {
            handleMonitor.leave();
         }
      }
   }

}

-----------------------

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**

 * @create 2021-02-15 15:15

 * @desc 测试自定义的 RateLimiterBucket

 **/
public class Test
{
   private static final AtomicInteger data = new AtomicInteger(0);
   private static final RateLimiterBucket bucket = new RateLimiterBucket();

   public static void main(String[] args)
   {
      //启动 10 个线程模拟高并发的业务请求
      for(int i = 0 ; i < 20 ; i++)
      {
         new Thread(
               ()->
               {
                  while(true)
                  {
                     bucket.submitRequest(data.getAndIncrement());
                     try
                     {
                        TimeUnit.SECONDS.sleep(3);
                     }
                     catch (InterruptedException e)
                     {
                        e.printStackTrace();
                     }
                  }
               }
         ).start();
      }
      //启动 10 个线程模拟匀速地对漏桶中的请求进行处理
      for(int i = 0 ; i < 10 ; i++)
      {
         new Thread(
               ()->
               {
                  while(true)
                  {
                     bucket.handleRequest(System.out::println);
                  }
               }
         ).start();
      }
   }
}

你可能感兴趣的:(多线程)