Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带有静态字符串的线程安全Servlet_Java_Node.js_Multithreading_Servlets_Thread Safety - Fatal编程技术网

Java 带有静态字符串的线程安全Servlet

Java 带有静态字符串的线程安全Servlet,java,node.js,multithreading,servlets,thread-safety,Java,Node.js,Multithreading,Servlets,Thread Safety,我已经查看了一个聊天服务器的示例,其中包含节点JS和套接字IO。在该示例中,服务器使用了一个简单的历史变量来保存聊天历史数据。由于节点Js是单线程的,所以一切都很好。(如果您对node JS不感兴趣,可以忽略上面的node JS示例:)下面我将用java进行解释) 考虑下面的servlet,它从请求中获取消息字符串并将其添加到字符串中。此代码可能是聊天服务器的一个示例。它从请求中获取用户消息,并将其全部保存到历史记录字符串中,其他客户端可以读取它 public class ChatServlet

我已经查看了一个聊天服务器的示例,其中包含节点JS和套接字IO。在该示例中,服务器使用了一个简单的历史变量来保存聊天历史数据。由于节点Js是单线程的,所以一切都很好。(如果您对node JS不感兴趣,可以忽略上面的node JS示例:)下面我将用java进行解释)

考虑下面的servlet,它从请求中获取
消息
字符串并将其添加到字符串中。此代码可能是聊天服务器的一个示例。它从请求中获取用户消息,并将其全部保存到
历史记录
字符串中,其他客户端可以读取它

public class ChatServlet implements Servlet {

    private static String history = "";    

    public void service(ServletRequest request, ServletResponse response)
         history = history.concat(request.getParameter("message"));
    }

}
理论上,此代码不是线程安全的,因为它使用了
全局静态变量()

然而,我已经用jMeter测试了上面的代码,其中有很多并发请求,历史记录字符串总是存储所有消息(因此没有丢失或重写客户机消息),并且没有出现任何问题! 我没有使用线程,所以我想知道我是否遗漏了一些东西!上述代码是线程安全的,可以信任


它不是线程安全的。非线程安全的代码不能保证失败,但也不能保证工作。

它不是线程安全的。非线程安全的代码不能保证失败,但也不能保证工作。

不,不是。线程安全漏洞可能很难触发——也许你的程序会错过十亿分之一的消息,或者它永远不会碰巧错过一条消息。但是,如果它是线程安全的,那么它将保证永远不会发生

您可以简单地使用
synchronized
块来确保一次只有一个线程访问
历史记录,如下所示:

synchronized(ChatServlet.class) {
    history = history.concat(request.getParameter("message"));
}
这意味着:锁定
ChatServlet.class
,将消息添加到历史记录中,然后解锁
ChatServlet.class

你不能让两个线程同时锁定同一个对象——如果他们尝试,其中一个线程将继续,其余线程将等待第一个线程解锁对象(然后另一个线程将继续,其余线程将等待第一个线程解锁对象,依此类推)


还要确保只读取
同步(ChatServlet.class)
块中的
历史记录
——否则,不能保证读取线程会看到最新更新。

不,不是。线程安全漏洞可能很难触发——也许你的程序会错过十亿分之一的消息,或者它永远不会碰巧错过一条消息。但是,如果它是线程安全的,那么它将保证永远不会发生

您可以简单地使用
synchronized
块来确保一次只有一个线程访问
历史记录,如下所示:

synchronized(ChatServlet.class) {
    history = history.concat(request.getParameter("message"));
}
这意味着:锁定
ChatServlet.class
,将消息添加到历史记录中,然后解锁
ChatServlet.class

你不能让两个线程同时锁定同一个对象——如果他们尝试,其中一个线程将继续,其余线程将等待第一个线程解锁对象(然后另一个线程将继续,其余线程将等待第一个线程解锁对象,依此类推)


另外,请确保只读取
同步(ChatServlet.class)
块中的
历史记录
——否则,无法保证读取线程将看到最新更新。

正如其他人所确认的,这确实不是线程安全的,因为它不可信。JVM实现中的一些怪癖可能会使它成为一个可行的servlet,但不能保证它能在另一个JVM甚至在另一个时间工作

要添加到各种建议的实现中,这里有一个AtomicReference:

AtomicReference<String> history = new AtomicReference<>("");

public void service(ServletRequest request, ServletResponse response)
     history.updateAndGet(h -> h.concat("123"));
}
AtomicReference history=新的AtomicReference(“”);
公共作废服务(ServletRequest请求、ServletResponse响应)
history.updateAndGet(h->h.concat(“123”);
}

正如其他人所确认的,这确实不是线程安全的,因为它不可信。JVM实现中的一些怪癖可能会使它成为一个可行的servlet,但不能保证它能在另一个JVM甚至在另一个时间工作

要添加到各种建议的实现中,这里有一个AtomicReference:

AtomicReference<String> history = new AtomicReference<>("");

public void service(ServletRequest request, ServletResponse response)
     history.updateAndGet(h -> h.concat("123"));
}
AtomicReference history=新的AtomicReference(“”);
公共作废服务(ServletRequest请求、ServletResponse响应)
history.updateAndGet(h->h.concat(“123”);
}