【问题标题】:Thread Safe Servlet With a Static String带有静态字符串的线程安全 Servlet
【发布时间】:2015-07-12 10:07:08
【问题描述】:

我在http://ahoj.io/nodejs-and-websocket-simple-chat-tutorial 上查看了一个带有 Node JS 和套接字 IO 的聊天服务器示例。在该示例中,服务器使用了一个简单的历史变量来保存聊天历史数据。由于 Node Js 是单线程的,所以一切正常。 (如果你对 node js 不感兴趣,可以忽略上面的 node JS 示例:)我将在下面用 java 解释)

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

public class ChatServlet implements Servlet {

    private static String history = "";    

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

}

理论上,此代码不是线程安全的,因为它使用了 global static 变量 (How do servlets work? Instantiation, sessions, shared variables and multithreading) 。

但是,我已经使用 jMeter 测试了上面的代码,其中包含大量并发请求,并且历史字符串始终存储所有消息(因此没有客户端消息丢失或覆盖),并且没有出错! 我没有使用线程,所以我想知道我是否在这里遗漏了什么!上面的代码是线程安全的,是否可信。


【问题讨论】:

    标签: java node.js multithreading servlets thread-safety


    【解决方案1】:

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

    为了增加各种建议的实现,这里有一个 AtomicReference:

    AtomicReference<String> history = new AtomicReference<>("");
    
    public void service(ServletRequest request, ServletResponse response)
         history.updateAndGet(h -> h.concat("123"));
    }
    

    【讨论】:

      【解决方案2】:

      不,不是。线程安全错误可能很难触发 - 也许您的程序会错过十亿分之一的消息,或者它可能永远不会错过任何消息巧合。但是,如果它是线程安全的,则可以保证永远不会发生。

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

      synchronized(ChatServlet.class) {
          history = history.concat(request.getParameter("message"));
      }
      

      这意味着:锁定ChatServlet.class,将消息添加到历史记录,然后解锁ChatServlet.class

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

      还要确保只读取 historysynchronized(ChatServlet.class) 块内 - 否则,不能保证读取线程会看到最新更新。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-09-16
          • 2012-09-22
          • 2015-03-24
          • 1970-01-01
          • 2019-05-21
          • 1970-01-01
          • 2016-08-24
          相关资源
          最近更新 更多