在日常开发过程中,经常遇到对资源使用频度的限制,例如:某个接口只允许每秒调用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();
}
}
时间: 2024-10-14 00:46:32