Java 这段代码有缺陷吗?

Java 这段代码有缺陷吗?,java,servlets,concurrency,Java,Servlets,Concurrency,我编写了一个servlet,但是servlet还没有进入生产阶段 我在servlet的过滤器中添加了一个计数器,这样当并发请求的数量达到限制时,就不能再接受更多的人了。我担心一些无关紧要的情况,例如:假设系统已经达到49个并发请求50是最大值,在同步块中,它将布尔变量ok设置为True,然后在下一个实例中,多线程看到servlet可用,并冲入其中并突破限制 如果存在任何缺陷,请帮助检查此代码: public void doFilter(ServletRequest request, Servle

我编写了一个servlet,但是servlet还没有进入生产阶段

我在servlet的过滤器中添加了一个计数器,这样当并发请求的数量达到限制时,就不能再接受更多的人了。我担心一些无关紧要的情况,例如:假设系统已经达到49个并发请求50是最大值,在同步块中,它将布尔变量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);
        }

    }

一次最多允许在一个对象上同步一个线程。如果多个线程试图冲入一个同步块,则只有一个线程能够成功。此外,每个线程都有其ok的本地副本,每个线程都必须通过此块:

synchronized (lock) {
    ok = count < limit;
    if (ok) {
        count++;
    }
}
在测试ok变量的值之前。所以我认为这是相当安全的


这是好事,你也同步计数递减以后;这将确保count的值将被刷新到内存中,然后其他线程才能进入在锁上同步的块。

我宁愿在servletcontainer级别对其进行配置,也不愿尝试将某些内容组合在一起。一个有点像样的servletcontainer经过了全面测试,肯定已经准备好生产了

例如,Tomcat有一个maxThreads属性正好用于此目的。您可以在server.xml中的元素中设置它

这就限制了同时请求的数量,顺便说一句,默认为200。因此,当有第51个请求时,它只会被放入一个队列中,该队列的长度可以通过acceptCounts属性进行配置,直到第一个请求就绪为止。这也比503更便于用户使用

另见:
这是正确的,但您基本上是在重新设计java.util.concurrent.Semaphore:


这个类比您的手工解决方案效率更高,并且更好地表达了您的意图。

您的单元测试告诉了您什么?集成测试、压力测试或用户验收测试如何?或者,你打算根据网上一些随机工作人员的一些评论将其投入生产。你的公司一定是一个非常令人兴奋的工作场所:-如果一个人同时发送50个请求怎么办?其他人一定会遭受这种痛苦吗?这个计划远离UAT,它是第二个应急计划啊。嗯,我宁愿在容器级别配置它。监控可以由JMX完成。例如,Tomcat也只支持它:。有一些基于Java的API/工具可以很好地将其可视化,例如JavaMelody,它看起来越来越像是您必须与您的经理和/或服务器管理员更好地协调此类需求/问题。这显然不是开发人员的责任。+1:既然容器可以为您编写过滤器,为什么还要编写自己的过滤器呢?我们在生产中使用websphere。我不知道怎么做。服务器管理员是负责人。顺便说一下,Websphere使用Tomcat的分支作为servletcontainer。所以很多配置设置看起来都很熟悉。请告诉我如何在websphere中实现这一点。我在谷歌上搜索过,但没有看到在这个问题上没有任何进展,你随后提出的问题让我毛骨悚然,我有一个轻微的印象,你自己就是服务器管理员,或者你害怕真正的服务器管理员。这是怎么一回事?我必须帮你翻阅手册,这样你才能最终做正确的事情吗?许可证变量需要是静态的,所以需要在线程之间共享吗?恐怕在您的代码中,每个线程都有一个实例?我听说信号量会产生死锁,您确定要使用信号量吗?Servlet实例在线程之间共享。静态意味着变量保存在类对象上,每个类加载器只有一个加载该类的类加载器。servlet容器负责加载servlet并在请求线程之间共享实例。就产生死锁而言,信号量与锁数组处于同一条船上,从概念上讲,你可以将其看作是死锁。锁的组合不是很好,所以如果您使用一个锁,然后调用其他可能使用另一个锁的代码,那么您必须非常小心任何执行相反操作的代码。其次,必须在finally块中释放许可证或解锁锁,否则异常将导致许可证丢失,这可能导致最终的饥饿,看起来有点像死锁。
<Connector maxThreads="50" ...>
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
    }
  }
}