高并发情况下的简单Web服务器

3
这并不是一道作业题,而是我在网上发现的面试题。
Java代码如下:
public class SimpleWebServer{
  public static void handleRequest(Socket c)
  {
    //Process the request
  }

  public static void main(String[] args) throws IOException
  { 
    ServerSocket server=new ServerSocket(80);
    while(true)
    {
       final Socket connection=server.accept();
       Runnable task=new Runnable(){
          @Override
          public void run()
          {
            handleRequest(connection);
          }
       };
       new Thread(task).start();
    }
  }
}

问题是当高并发时可能会出现什么潜在问题?我的分析是:

  1. 它没有使用synchronized关键字,因此可能会发生竞争条件。
  2. 应该使用线程池,这样更有效率。
  3. 似乎对于每个传入的线程,该类总是创建一个新的ServerSocket,当高并发发生时,这将消耗大量空间?
2个回答

4
我看到的主要问题就是你所指出的那一个。基于请求的线程模型本质上是有缺陷的(正如 Nginx 和 lighttpd 在 Apache 之上被广泛采用所证明的)。在这里,改用 ExecutorService(可能由线程池支持)是个不错的选择。
通过从基于请求的线程模型转变为向 ExecutorService 提交任务,你将这个应用程序向事件驱动模型前进了一步。网络上有很多关于事件驱动模型优于基于线程模型的扩展性的资料。
handleRequest 方法使用 'synchronized' 是一种相当暴力的策略,具体取决于方法内部的细节,更精细的锁定策略(或无锁逻辑)会更好。你提到的 ServerSocket 创建仅发生一次于整个应用程序,因此这并不是一个实际的可扩展性问题。每个连接都会创建一个新的 Socket 实例,但这些实例非常廉价。从 JDK 6 的源代码来看,这包括分配 7 个布尔值、一个锁对象和检查一些内部状态,即可能不会成为问题。
基本上,你正在走在正确的轨道上!希望这能够有所帮助。

0

以下是潜在问题列表:

1)生成线程需要CPU周期,每个线程都有自己的数据结构占用内存。当一个线程阻塞时,JVM会保存其状态并选择另一个线程运行,并恢复所选线程的状态,这称为上下文切换。随着线程数量的增加,线程消耗的资源也越多。线程池被引入来解决这个问题,通过限制线程数量并重用线程而不是生成新线程。

2)最令人沮丧和重要的问题是使这些线程以同步方式共享或访问变量(例如状态)。很容易使这些变量不一致。因此,一些程序员更喜欢使用单线程环境(例如NIO)而不是多线程环境。

3)没有日志系统将使线程环境在您想要跟踪问题时更难调试。

4)您不需要每次想要接受新客户端时都实例化new serversocket(),因为它是一个共享的Serversocket实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接