2009-09-10 18 views
5

Tengo un servidor web propio en mi aplicación. Este servidor web genera un nuevo hilo para cada solicitud que entra en el socket para ser aceptado. Quiero que el servidor web espere hasta que se toque un punto específico en el hilo que acaba de crear.Sincronización en subprocesos para Java

He pasado por muchas publicaciones en este sitio y ejemplos en la web, pero no puedo hacer que el servidor web proceda después de que le digo al hilo que espere. Un ejemplo de código básico sería genial.

¿Es la palabra clave sincronizada la forma correcta de hacerlo? Si es así, ¿cómo se puede lograr esto? Los ejemplos de código están por debajo de mi aplicación:

servidor Web

while (true) { 
    //block here until a connection request is made 
    socket = server_socket.accept(); 

    try { 
    //create a new HTTPRequest object for every file request 
    HttpRequest request = new HttpRequest(socket, this); 

    //create a new thread for each request 
    Thread thread = new Thread(request); 

    //run the thread and have it return after complete 
    thread.run(); 

    /////////////////////////////// 
    wait here until notifed to proceed 
    /////////////////////////////// 
    } catch (Exception e) { 
    e.printStackTrace(logFile); 
    } 
} 

código de rosca

public void run() { 
    //code here 

    //notify web server to continue here 
} 

Actualización - código final es la siguiente. El HttpRequest se limita a llamar resumeListener.resume() cada vez que envío un encabezado de respuesta (por supuesto, también la adición de la interfaz como una clase separada y el método addResumeListener(ResumeListener r1) en HttpRequest):

porción Servidor Web

// server infinite loop 
while (true) { 

    //block here until a connection request is made 
    socket = server_socket.accept(); 

    try { 
    final Object locker = new Object(); 

    //create a new HTTPRequest object for every file request 
    HttpRequest request = new HttpRequest(socket, this); 

    request.addResumeListener(new ResumeListener() { 
     public void resume() { 
     //get control of the lock and release the server 
     synchronized(locker) { 
      locker.notify(); 
     } 
     } 
    }); 

    synchronized(locker) { 
     //create a new thread for each request 
     Thread thread = new Thread(request); 

     //run the thread and have it return after complete 
     thread.start(); 

     //tell this thread to wait until HttpRequest releases 
     //the server 
     locker.wait(); 
    } 
    } catch (Exception e) { 
    e.printStackTrace(Session.logFile); 
    } 
} 
+0

Así como una cuestión académica, ¿Por qué escribió su propio código de servidor web? – MattC

+0

La aplicación muestra contenido encriptado, así que básicamente al crear mi propio servidor web interno, puedo realizar la autenticación. Si un navegador externo intenta usar el mismo socket al que estoy transfiriendo los datos, no tendría las credenciales adecuadas que yo proporciono internamente si la solicitud proviene de mi aplicación. – Ken

+0

No veo cómo eso imposibilita el uso de un servidor web diferente: casi todos los servidores web admiten la autenticación basada en IP, entre otros mecanismos. – bdonlan

Respuesta

1

En primer lugar, me hago eco del sentimiento de los demás de que volver a inventar la rueda aquí probablemente dará lugar a una variedad de problemas para usted. Sin embargo, si quieres ir por este camino, de todos modos, lo que estás tratando de hacer no es difícil. ¿Has experimentado con Jetty?

Tal vez algo como esto:

public class MyWebServer { 

    public void foo() throws IOException { 
    while (true) { 
     //block here until a connection request is made 
     ServerSocket socket = new ServerSocket(); 

     try { 
     final Object locker = new Object(); 
     //create a new HTTPRequest object for every file request 
     MyRequest request = new MyRequest(socket); 
     request.addResumeListener(new ResumeListener() { 
      public void resume() { 
      locker.notify(); 
      } 
     }); 
     synchronized(locker){ 

      //create a new thread for each request 
      Thread thread = new Thread(request); 

      //start() the thread - not run() 
      thread.start(); 

      //this thread will block until the MyRequest run method calls resume 
      locker.wait(); 
     } 
     } catch (Exception e) { 
     } 

    } 
    } 
} 

public interface ResumeListener { 
    public void resume(); 
} 

public class MyRequest implements Runnable{ 
    private ResumeListener resumeListener; 

    public MyRequest(ServerSocket socket) { 
    } 

    public void run() { 
    // do something 
    resumeListener.resume(); //notify server to continue accepting next request 
    } 

    public void addResumeListener(ResumeListener rl) { 
    this.resumeListener = rl; 
    } 
} 
+0

Gracias por el ejemplo. Parece bastante sencillo y lo probaré también. Entiendo las inquietudes de implementar mi propio servidor web He examinado brevemente Jetty, pero no avancé con él. Jetty todavía es una posibilidad para el futuro, pero en este momento el hogar está teniendo un buen rendimiento. – Ken

7

Usted puede utilizar java.util.concurrent.CountDownLatch con un recuento de 1 para esto. Haga arreglos para que una instancia de la misma sea creada y compartida por el hilo primario y secundario (por ejemplo, créelo en el constructor HttpRequest, y una función miembro puede recuperarlo). A continuación, el servidor llama al await() y el hilo llega al countDown() cuando está listo para liberar su principal.

+0

Gracias por la sugerencia, intentaré implementar de esta manera. Parece lo suficientemente simple. – Ken

3

Probablemente necesite utilizar Java Condition. A partir de los documentos:

condiciones (también conocidos como condición colas o variables de condición) proporcionan un medio para un hilo de suspender ejecución ("esperar") hasta que sea notificado por otro hilo que algún estado condición ahora puede ser cierto

+1

Las variables de condición solo son un poco difíciles de codificar; también necesita un candado asociado y una bandera para saber cuándo detener el bucle y el bloqueo. Además, no es necesario usar la clase de condición directamente; simplemente use el monitor implícito en cada Objeto ... – bdonlan

+0

Además, para aclarar un poco - Condición/Bloqueo hacer para un sistema más explícito, pero uno que es independiente de los monitores incorporados utilizados por 'sincronizado' y' Object.wait() '. Serían útiles si necesita múltiples variables de condición asociadas a un solo bloqueo, pero en este caso es demasiado exagerado. – bdonlan

+0

En realidad 'Condition' es una interfaz, solo lo señalé, ya que usar una clase de implementación será necesario en la práctica. La página a la que me he vinculado tiene un ejemplo con 'ReentrantLock's. –

-3

Ejecutar bajo un depurador y establecer un punto de interrupción?

Si no es posible, lea una línea de System.in?

+0

No tengo idea de cómo esto se relaciona con la pregunta .... –

Cuestiones relacionadas