Java 如何以线程安全的方式将递增的用户ID分配给新用户?

Java 如何以线程安全的方式将递增的用户ID分配给新用户?,java,servlets,Java,Servlets,我刚刚开始学习Java,在创建Java服务器时遇到了一个问题 在HTML上,应该有一个表单,JavaScript witch每秒提交一次表单(通过POST方法)。表单应该有一个隐藏字段,其值为用户ID。服务器应该在请求中查找用户ID。它应该给新用户提供新的ID,给访问过的用户显示他们的ID 每次提交表格后,铭文变为:空,2,空,2,空,2。。。。代码如下: public class ServerConnect extends AbstractHandler{ private A

我刚刚开始学习Java,在创建Java服务器时遇到了一个问题

在HTML上,应该有一个表单,JavaScript witch每秒提交一次表单(通过POST方法)。表单应该有一个隐藏字段,其值为用户ID。服务器应该在请求中查找用户ID。它应该给新用户提供新的ID,给访问过的用户显示他们的ID

每次提交表格后,铭文变为:空,2,空,2,空,2。。。。代码如下:

public class ServerConnect extends AbstractHandler{
         private AtomicInteger ids = new AtomicInteger(0);    
         private String userId;

         public void handle(String target,
         Request baseRequest,
         HttpServletRequest request,
         HttpServletResponse response)    throws IOException, ServletException
         {

             response.setContentType("text/html;charset=utf-8");
             response.setStatus(HttpServletResponse.SC_OK);
             baseRequest.setHandled(true);
             response.getWriter().println(PageGenerator.generateForm(userId));
             userId = request.getParameter("userId");

             if (userId == null){
                 ids.getAndIncrement();
                 userId = ids.toString();
             }        
          }

         public static void main(String[] args) throws Exception {

               Server server = new Server(8080);
               server.setHandler(new ServerConnect());
               server.start();
               server.join();
        }
}

public class PageGenerator {

    public static String generateForm(String val){
        String htmlCode = null;

        htmlCode = "...
             <script>
                function reload(){ 
                   document.forms['MainForm'].submit();
                }
                setTimeout("reload()", 1000); 
             </script>    
             .... + val + ...
             <form id='MainForm' method = 'POST'>
                 <input type = "hidden" name = "userId" value = \""+ val + \""> 
             <form>
                             ...       
    return htmlCode;
    }    

}
公共类ServerConnect扩展了AbstractHandler{
私有AtomicInteger ID=新的AtomicInteger(0);
私有字符串用户标识;
公共无效句柄(字符串目标,
请求baseRequest,
HttpServletRequest请求,
HttpServletResponse响应)引发IOException,ServletException
{
setContentType(“text/html;charset=utf-8”);
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println(PageGenerator.generateForm(userId));
userId=request.getParameter(“userId”);
if(userId==null){
id.getAndIncrement();
userId=ids.toString();
}        
}
公共静态void main(字符串[]args)引发异常{
服务器=新服务器(8080);
setHandler(新的ServerConnect());
server.start();
join();
}
}
公共类页面生成器{
公共静态字符串生成器窗体(字符串val){
字符串htmlCode=null;
htmlCode=“。。。
函数重载(){
document.forms['MainForm'].submit();
}
setTimeout(“reload()”,1000);
..…+val+。。。
...       
返回htmlCode;
}    
}

我无法理解为什么用户ID等于2,为什么在用户获得ID后,它的值会变为null,然后又变为2,这似乎是在解析用户ID之前呈现页面。在选中
if(userId==null)

另外,您应该了解
AtomicLong.getAndIncrement()
是一个复合操作,类似于
i++
(但它是一个单一的原子操作)

因此,您需要有如下代码:

if (userId == null){
     userId = ids.getAndIncrement();
} 
最后,我不确定
AbstractHandler
的生命周期,但可以合理地假设Jetty每隔一次请求就会实例化一个类的新实例。由于
ids
的作用域是“实例”字段,因此它会被新请求丢弃(从而有效地重置)

在此处编辑关于Jetty线程模型的答案:

要解决这个问题,您需要将
ids
声明为
static final
(从而有效地使其成为一个“单例”ID生成器),以使其在多个请求中生存。对于玩具应用程序来说,这是一种不错的方法,但不需要在生产代码中执行