释放锁后强制下一个线程的最短等待时间?
Enforce minimum wait time for next thread after the lock has been released?
我正在向网络服务发出请求,请求之间的最短等待时间为 200 毫秒。我想在我的多线程应用程序中强制执行此策略。目前我的应用程序中有这段代码:
lock.lock();
String resp = httpUtility.makeGetRequest(serviceUrl); //make request to service
lock.unlock() //timer should start after thread exits this
如果一个线程来到这里,我希望它立即通过。如果线程退出 lock.unlock()
那么我希望它启动一个 200 毫秒的计时器。在那段时间里,任何线程都不应超过 lock.lock()
.
我也希望队列公平,所以不能只用wait()
和notify()
。另一方面,Lock
也不好,因为只有获取线程才能释放 Lock
,我不想让线程停顿 200 毫秒。
实现这个的好方法是什么?
我会创建一个 while (true)
循环,在单独的线程中执行每个新请求,然后休眠 200 毫秒,例如像
try {
while (true) {
executor.execute(requestQueue.take());
Thread.sleep(200);
}
} catch (InterruptedException ex) {...}
Artyom 的回答很好,但我在阅读您的问题时表示您有多个线程想要发出 GET 请求。
在这种情况下,创建一个实现 Runnable 的 RequestHandler class,例如线程本身。让每个工作线程获得此 RequestHandler class 的单例实例。类似于:
RequestHandler requestHandler = new RequestHandler();
new Thread(requestHandler).start(); //your one and only of this class
然后,在 RequestHandler 中创建一个简单的 list/queue。当一个 Worker 创建一个新的请求时,它只是简单地排队一个请求:
class RequestHandler implements Runnable {
List<String> requestUrls = new ArrayList<String>();
public void submitRequest(String url) {
System.out.println("===>Request incoming for " + url);
requestUrls.add(url);
}
现在,添加您的 运行 方法以在请求进入时处理队列。将最早的 url 从队列中取出,发出请求,然后休眠 200 毫秒。
@Override
public void run() {
while (true) {
String currentRequestUrl = null;
if (!requestUrls.isEmpty()) {
currentRequestUrl = requestUrls.remove(0);
} else {
try {
Thread.sleep(1); //give CPU a break
} catch (InterruptedException e) {
}
}
if (currentRequestUrl != null) {
System.out.println("##Simulating calling " + currentRequestUrl);
System.out.println("##Request to " + currentRequestUrl + " is complete.");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
}
所以现在,每次创建 Worker 时,请确保将其传递给此 "singleton" RequestHandler。
class Worker implements Runnable {
private String url;
private RequestHandler requestHandler;
Worker(String url, RequestHandler requestHandler) {
this.url = url;
this.requestHandler = requestHandler;
}
并且当 worker 准备好提交请求时,它会调用 RequestHandler
requestHandler.submitRequest(url);
我正在向网络服务发出请求,请求之间的最短等待时间为 200 毫秒。我想在我的多线程应用程序中强制执行此策略。目前我的应用程序中有这段代码:
lock.lock();
String resp = httpUtility.makeGetRequest(serviceUrl); //make request to service
lock.unlock() //timer should start after thread exits this
如果一个线程来到这里,我希望它立即通过。如果线程退出 lock.unlock()
那么我希望它启动一个 200 毫秒的计时器。在那段时间里,任何线程都不应超过 lock.lock()
.
我也希望队列公平,所以不能只用wait()
和notify()
。另一方面,Lock
也不好,因为只有获取线程才能释放 Lock
,我不想让线程停顿 200 毫秒。
实现这个的好方法是什么?
我会创建一个 while (true)
循环,在单独的线程中执行每个新请求,然后休眠 200 毫秒,例如像
try {
while (true) {
executor.execute(requestQueue.take());
Thread.sleep(200);
}
} catch (InterruptedException ex) {...}
Artyom 的回答很好,但我在阅读您的问题时表示您有多个线程想要发出 GET 请求。
在这种情况下,创建一个实现 Runnable 的 RequestHandler class,例如线程本身。让每个工作线程获得此 RequestHandler class 的单例实例。类似于:
RequestHandler requestHandler = new RequestHandler();
new Thread(requestHandler).start(); //your one and only of this class
然后,在 RequestHandler 中创建一个简单的 list/queue。当一个 Worker 创建一个新的请求时,它只是简单地排队一个请求:
class RequestHandler implements Runnable {
List<String> requestUrls = new ArrayList<String>();
public void submitRequest(String url) {
System.out.println("===>Request incoming for " + url);
requestUrls.add(url);
}
现在,添加您的 运行 方法以在请求进入时处理队列。将最早的 url 从队列中取出,发出请求,然后休眠 200 毫秒。
@Override
public void run() {
while (true) {
String currentRequestUrl = null;
if (!requestUrls.isEmpty()) {
currentRequestUrl = requestUrls.remove(0);
} else {
try {
Thread.sleep(1); //give CPU a break
} catch (InterruptedException e) {
}
}
if (currentRequestUrl != null) {
System.out.println("##Simulating calling " + currentRequestUrl);
System.out.println("##Request to " + currentRequestUrl + " is complete.");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
}
所以现在,每次创建 Worker 时,请确保将其传递给此 "singleton" RequestHandler。
class Worker implements Runnable {
private String url;
private RequestHandler requestHandler;
Worker(String url, RequestHandler requestHandler) {
this.url = url;
this.requestHandler = requestHandler;
}
并且当 worker 准备好提交请求时,它会调用 RequestHandler
requestHandler.submitRequest(url);