2013-05-15 1 views
3

Ce n'est pas un devoir, mais une question d'entrevue que j'ai trouvée sur le Web.Serveur Web simple lorsque la haute simultanéité est atteinte

Le code java est:

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(); 
    } 
    } 
} 

La question est ce problème potentiel, il y aura quand il y a un forte concurrence? Mon analyse est la suivante:

  1. Il n'a pas utilisé de mot-clé synchronisé, il peut donc y avoir des situations où les conditions de concurrence se produisent.
  2. Il devrait utiliser un pool de threads, ce qui est plus efficace.
  3. Il semble que pour chaque thread entrant, la classe crée toujours une nouvelle ServerSocket, qui consommera beaucoup d'espace en cas de forte simultanéité.

Répondre

4

Le problème principal que je vois avec ceci, est celui que vous avez identifié. Le modèle thread-per-request est intrinsèquement erroné (comme en témoigne l'adoption à grande échelle de Nginx et de lighttpd sur Apache). Passer à un ExecutorService (probablement soutenu par un pool de threads) serait un bon choix ici. En passant d'une requête par tâche à une soumission simple d'une tâche à un service ExecutorService, vous déplacez cette application vers un modèle basé sur les événements. Il y a beaucoup de matériel sur le web prônant les vertus d'évolutivité des modèles basés sur les événements basés sur des threads. L'utilisation de 'synchronized' sur la méthode handleRequest est une jolie tactique de force brute, et en fonction des intensions particulières de la méthode, une stratégie de verrouillage plus granulaire (ou logique sans verrou) serait préférable. La création de ServerSocket que vous avez mentionnée ne se produit qu'une fois pour l'application, donc ce n'est pas vraiment un problème d'évolutivité. La méthode accept crée une nouvelle instance Socket pour chaque connexion, mais celles-ci sont bon marché. En regardant la source du JDK 6, cela consiste à allouer 7 booléens, un verrou Object, et à vérifier un état interne - c'est-à-dire, cela ne va probablement pas poser de problème.

Fondamentalement, vous êtes sur la bonne voie! J'espère que cela t'aides.

0

Voici la liste des problèmes potentiels

1) d'un thread utilise des cycles CPU et chaque thread a ses propres structures de données qui consomme de la mémoire. Lorsqu'un thread bloque, JVM enregistre son état et sélectionne un autre thread à exécuter et restaure l'état du thread choisi, il est appelé le commutateur de contexte. À mesure que le nombre de threads augmente, davantage de ressources sont consommées par les threads. Threadpool a été introduit pour résoudre ce problème en limitant le nombre de threads et en réutilisant les threads au lieu de générer de nouveaux threads.

2) Le problème le plus frustrant et le plus important est de faire en sorte que ces threads partagent ou accèdent à une variable (par exemple, un état) de manière synchronisée. Il est facile de rendre ces variables incohérentes. Par conséquent, certains programmeurs préfèrent utiliser un environnement à un seul thread (par exemple, NIO) au lieu d'un environnement multi-thread.

3) Le fait de ne pas avoir de système de journalisation va rendre l'environnement threadé plus difficile à déboguer lorsque vous voulez tracer un problème.

4) Vous n'avez pas besoin d'instancier de nouveau serversocket() chaque fois que vous voulez accepter un nouveau client puisqu'il s'agit d'une instance Serversocket partagée.

Questions connexes