我编写了一个servlet,但是servlet尚未处于生产阶段。
我在servlet的Filter中添加了一个计数器,这样当并发请求数达到限制时,就不能再接受任何人了。我担心一些边缘情况,例如:假设系统已经达到49个并发请求(50个是最大值),并且在synchronized块中它使布尔变量“ok”为True,然后在下一个实例中,多个线程看到servlet是可用的,赶紧进入并打破限制。
如果有任何缺陷,请帮助检查此代码:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// pass the request along the filter chain
conditionalInfoLog(logEnabled, "Incoming request...");
conditionalInfoLog(logEnabled, "Number of concurrent request(s): " + count);
boolean ok;
synchronized (lock) {
ok = count < limit;
if(ok){
count++;
}
}
if (ok) {
try{
// let the request through and process as usual
conditionalInfoLog(logEnabled, "Request accepted and processing, number of concurrent request(s): " + count);
chain.doFilter(request, response);
}catch(Exception ex){
conditionalErrorLog(logEnabled, ex.getMessage());
String xmlStr = genXmlErrMsg(ex.getMessage());
response.setContentType("text/xml");
response.getWriter().print(xmlStr);
}finally{
synchronized (lock) {
count--;
}
conditionalInfoLog(logEnabled, "End of request. Number of concurrent request(s): " + count);
}
} else {
// handle limit case, e.g. return status code 503
conditionalInfoLog(logEnabled, busyMsg);
String xmlStr = genXmlErrMsg(busyMsg);
response.setContentType("text/xml");
response.getWriter().print(xmlStr);
}
}
答案 0 :(得分:5)
我宁愿在servletcontainer级别配置它而不是试图拼凑一些东西。一个不错的servletcontainer经过全面测试,确保生产就绪。
例如,Tomcat完全具有maxThreads
属性用于此目的。您可以在<Connector>
中的server.xml
元素中进行设置。
<Connector maxThreads="50" ...>
这限制了同时请求的数量(顺便说一下,默认为200)。因此,当有第51个请求时,它只是放入一个队列(其长度可由acceptCounts
属性配置),直到第一个准备好。这也比503更加用户友好。
答案 1 :(得分:3)
这是正确的,但你基本上是在重新发明java.util.concurrent.Semaphore
:
class MyFilter {
final Semaphore permits = new Semaphore(50);
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (permits.tryAcquire()) {
try {
… // execute
} finally {
permits.release();
}
} else {
… // handle limit case, e.g. return status code 503
}
}
}
此课程比您的手动解决方案更有效,无论如何都能更好地表达您的意图。
答案 2 :(得分:0)
一次最多允许一个线程同步一个对象。如果有几个线程试图“冲进”同步块,那么只有一个线程可以实现。此外,每个线程都有ok
的本地副本,每个线程都必须通过此块:
synchronized (lock) {
ok = count < limit;
if (ok) {
count++;
}
}
之前它可以测试它的ok
变量的值。所以我觉得这很安全。
稍后同步count
的减量也是很好的;这将确保在任何其他线程可以进入在count
上同步的块之前,lock
的值将被刷新到内存。