注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

逍遥子 曰:

得失失得 何必患得患失 舍得得舍 不妨不舍不得

 
 
 

日志

 
 

[原] 一个简单限速器的java实现[1]  

2015-04-23 15:20:17|  分类: JAVA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
在日常开发过程中,经常遇到对资源使用频度的限制,例如:某个接口只允许每秒调用300次,或者某个资源对象只允许每秒使用300等等,下面是一个简单的限速器的java实现,它可以实现对一个资源在若干时间(毫秒内)只允许多少次访问,具体实现代码如下:

package test_tmp;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Semaphore;

public class SpeedLimiter<T> {
//两个参数maxUsedLimited和timeLimited用于限制访问速度,表示在timeLimited毫秒内,只允许资源resource被使用maxUsedLimited次
public SpeedLimiter(int maxUsedLimited, int timeLimited, T resource)
{
this.maxUsedLimited = maxUsedLimited;
this.timeLimited = timeLimited;
this.resource = resource;
m_semaphore = new Semaphore(maxUsedLimited * 1000 / timeLimited);
}
ConcurrentLinkedDeque<Long> statisticsInfo = new ConcurrentLinkedDeque<Long>();
T resource = null;
//下面两个参数用于限制访问速度
private int maxUsedLimited;
private int timeLimited;//统计的时间长度为1000毫秒,即1秒

//用信号量来限制资源的访问
private Semaphore m_semaphore = null;

public synchronized T consume()
{
if(statisticsInfo.size() >= maxUsedLimited)
{//已经有了使用时间记录
long ti = statisticsInfo.getLast() - statisticsInfo.getFirst();
if(ti < timeLimited)
{//已经超限制了,即次数达到了,但是时间还没到STATISTICS_TIME,说明申请的太快了,还差多少时间就sleep多少时间
System.out.println("-------------资源访问受限,当前已经在"+ ti +"毫秒内访问了" + statisticsInfo.size() + "次资源");
safeSleep(timeLimited - ti);
}
statisticsInfo.removeFirst();//总次数到了,每次都把最老的那个时间去掉
}
//先申请再记录时间
try {
m_semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
statisticsInfo.add(System.currentTimeMillis());
return resource;
}

public void returnResource()
{
System.out.println("-------------回收一个资源,当前资源可用数:" + m_semaphore.drainPermits());
m_semaphore.release();
}

private void safeSleep(long sleepTime)
{
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}

}


下面是对上述限速器的使用示例: 
首先是测试线程的代码:

package test_tmp;


public class TestSpeedLimitedThread<T> extends Thread {
SpeedLimiter<T> limiter = null;
public TestSpeedLimitedThread(SpeedLimiter<T> limiter)
{
this.limiter = limiter;
}
public void run()
{
long i = 0;
while(true)
{
T tmpResource = limiter.consume();
System.out.println("thread id: " + currentThread().getId() + " : " +(i+1) + ": 已经获取到资源:" + tmpResource);
i++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
limiter.returnResource();
}
}
}

下面是主测试函数的代码:

public static void testSpeedLimiter()
{
String resource = "myresource";
SpeedLimiter<String> test = new SpeedLimiter<String>(50, 1000, resource);
TestSpeedLimitedThread<String> testThread1 = new TestSpeedLimitedThread<String>(test);
testThread1.start();
TestSpeedLimitedThread<String> testThread2 = new TestSpeedLimitedThread<String>(test);
testThread2.start();
TestSpeedLimitedThread<String> testThread3 = new TestSpeedLimitedThread<String>(test);
testThread3.start();

try {
testThread1.join();
testThread2.join();
testThread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}


  评论这张
 
阅读(672)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017