在
http://blog.csdn.net/houjixin/article/details/45222081 或者
http://houjixin.blog.163.com/blog/static/3562841020153233201796/
中实现的限速器,需要内部维持一个容器来记录每次访问的时间,在每次新请求资源时通过计算容器中首尾两个时间的差值以及容器中的访问次数来确定是否超速,其实这种实现方法有两个缺点:
(1)只比较了平均速度,没有比较瞬时速度,假如限速器限制每秒钟最多访问1000次,如果前500毫秒访问了999次,后500毫秒就访问一次,这种情况就无法进行判断;
(2)实现方法比较复杂。
因此,在本文中实现的是基于间隔时间的限速方法,它的基本思路为:假如限速器限制的最大访问速度为每秒100,则可认为,相邻两次访问的间隔时间不能小于10毫秒,因此,在每次访问资源时只需要比较与上次访问的时间间隔即可,相关实现代码为:
package test_tmp;
import java.util.concurrent.Semaphore;
//使用两次相邻使用的间隔时间进行判断
import java.util.concurrent.atomic.AtomicLong;
public class SpeedLimiter2<T> {
private static long INIT_TIME = 0;
//参数maxUsedFrequency,表示对资源resource的最大访问速度为每秒maxUsedFrequency次
public SpeedLimiter2(int maxUsedFrequency, T resource)
{
this.resource = resource;
this.interval = 1000 / maxUsedFrequency;//表示相邻两次之间的访问间隔时间(毫秒)
m_semaphore = new Semaphore(maxUsedFrequency);
lastUsedTime = new AtomicLong(INIT_TIME);
}
private AtomicLong lastUsedTime = null;
private long interval = 0;//相邻两次申请资源的最大间隔时间
private T resource = null;
//用信号量来限制资源的访问
private Semaphore m_semaphore = null;
//同步申请资源
public synchronized T consume()
{
long curTime = System.currentTimeMillis();
long curInterVal = curTime - lastUsedTime.get();
if(curInterVal < interval)
{//请求速度太快了,需要休息一下
System.out.println(String.format("+++++++++++++++need sleep: interval:%d - %d = %d",interval, curInterVal, (interval - curInterVal)));
safeSleep(interval - curInterVal);
}
//申请资源
try {
m_semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
lastUsedTime.getAndSet(System.currentTimeMillis());//记录下申请资源成功的时间
return resource;
}
public void returnResource()
{
System.out.println("-------------回收一个资源");
m_semaphore.release();
}
private void safeSleep(long sleepTime)
{
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
相关的测试线程的代码为:
package test_tmp;
public class TestSpeedLimitedThread2<T> extends Thread {
SpeedLimiter2<T> limiter = null;
public TestSpeedLimitedThread2(SpeedLimiter2<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";
SpeedLimiter2<String> test = new SpeedLimiter2<String>(50, resource);
TestSpeedLimitedThread2<String> testThread1 = new TestSpeedLimitedThread2<String>(test);
testThread1.start();
TestSpeedLimitedThread2<String> testThread2 = new TestSpeedLimitedThread2<String>(test);
testThread2.start();
TestSpeedLimitedThread2<String> testThread3 = new TestSpeedLimitedThread2<String>(test);
testThread3.start();
try {
testThread1.join();
testThread2.join();
testThread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
时间: 2024-10-24 19:51:05