martes, 6 de marzo de 2012

4.4 SINCRONIZACIÓN DE HILOS

4.4 SINCRONIZACION DE HILOS
     Cuando se están utilizando hilos múltiples,algunas veces es necesario coordinar las actividades de dos o más. El proceso por el cual se logra esto se llama sincronización. La razón más común para la sincronización es cuando dos o mas hilos necesitan acceso a un recurso compartido que  sólo puede ser utilizado por un hilo a la vez. Otra razón para la sincronización es cuando un hilo está esperando un evento causado por otro hilo. En este caso, debe de haber algún medio por el cual el primer hilo se mantenga en estado suspendido hasta que el evento ocurra.
     La sincronización esta soportada por la palabra clave synchronized y por unos cuantos métodos bien definidos que tienen todos los objetos.

USO DE MÉTODOS SYNCHRONIZED
     Cuando se llama al método Synchronized , el hilo que llama ingresa al monitor de objeto, que entonces bloquea el objeto. Mientras esta bloqueado ningún otro hilo puede ingresar al método, ni ingresar algún otro método sincronizado definido por el objeto. Cuando el hilo retorna del método, el monitor desbloquea el objeto permitiendo que sea usado por el próximo hilo.

Los puntos clave de un método sincronizado son:
  • Un método sincronizado se crea precediendo su declaración con synchronized.
  • Para cualquier objeto dado,una vez un método sincronizado ha sido llamado se bloquea el objeto, y los métodos no sincronizados dentro del mismo objeto pueden ser utilizados por otros hilos en ejecución.
  • Otros hilos que traten de llamar un objeto sincronizado en uso ingresaría en un estado de espera, hasta que el objeto se desbloquea.
  • Cuando un hilo sale del método sincronizado, el objeto se desbloquea.
DECLARACIÓN SYNCHRONIZED
    La creación del método Synchronized dentro de las clases creadas por nosotros mismos es fácil y eficiente sin embargo no trabaja en todos los casos. Por ejemplo, podemos querer sincronizar el acceso a algún método que no este modificado por Synchronized ; esto ocurre cuando queremos utilizar una clase que no fue creada por nosotros sino por un tercero, y no tenemos acceso al código fuente.
     La solución para este problema es poner llamadas a los métodos definidos por esa clase dentro de un bloque Synchronized. La forma general de un bloque  Synchronized es:
synchronized  (objeto){
                                   //declaraciones para ser sincronizadas
                                                            }

     Aquí objeto hace referencia al objeto que va a ser sincronizado. Un objeto sincronizado asegura que una llamada a un método, ocurra solo después de que el hilo que llama ha ingresado al monitor del objeto.

EJEMPLO:
/**
uso de synchronized en el control de accesos
 */
class SumArray {
          private int sum;

          synchronized int SumArray(int nums[]){
           sum=0; //inicializa sum

           for (int i=0;i<nums.length;i++){
               sum= nums[i];
                System.out.println ("Ejecucion total para" + Thread.currentThread().getName() + " es " + sum);

          try{
               Thread.sleep(10); //permite el suicheo de tareas
          }
         catch (InterruptedException exc){
                  System.out.println ("Hilo principal interrumpido ");
           }
        }
     return sum;
  }    
}
class MyThread implements Runnable{
                 Thread thrd;
                 static  SumArray sa=new SumArray();
                 int a[];
                 int answer;

                / /contruye un nuevo hilo
              MyThread(String name,int nums[]){
                       thrd= new Thread (this,name);
                       thrd.start(); //arranca el hilo
                        a= nums;
              }

             //inicia la ejecucion del nuevo hilo
            public void run(){
                       int sum;
                       System.out.println ("Suma para " + thrd.getName() + " es " + answer);
                       System.out.println (thrd.getName() + "terminando");
          }

}
class Sync{
          public static void main (String[] args) {
          int a[]={1,2,3,4,5};

          MyThread mt1= new MyThread ("Hijo #1",a);
          MyThread mt2= new MyThread ("Hijo #2",a);
         }
}


    El programa anterior crea 3 clases. La primera es SumArray que contiene el método SumArray (), que suma un arreglo entero. La segunda clase es MyThread, que utiliza un objeto de tipo SumArray para obtener la suma de un arreglo entero. Finalmente, la clase Sync crea dos hilos, y permite que ellos calculen la suma de un arreglo entero.


    Dentro de sumArray (), se llama sleep() para permitir que ocurra un cambio de tarea, pero de hecho no es posible. Porque sumArray () está sincronizada. Solamente un hilo a la vez puede utilizarla. De modo que cuando el segundo hilo hijo comience su ejecución, no ingresa sumArray() hasta después que el primer hilo hijo esté terminado. Esto asegura que se produzca el resultado correcto. 


COMUNICACIÓN DE HILOS UTILIZANDO NOTIFY (), WAIT ()                                      Y NOTIFY ALL ()
     Los métodos wait (), notify () y notify all () son parte de todos los objetos porque están implementados por la clase Object. Estos métodos sólo pueden ser llamados desde el interior de un método Synchronized. A continuación se presenta como se utilizan. Cuando un hilo está temporalmente bloqueado para ejecución, llama a wait (). Esto hace que el hilo vaya a dormir y que el monitor para ese objeto se libere, permitiendo que otro hilo utilice el objeto. Luego en otro punto, el hilo dormido despierta cuando algún otro hilo ingresa al monitor, y llama a notify () o a notify All (). Un llamado a notify () reanuda el hilo. Una llamada a notify All () reanuda todos los hilos de más alta prioridad gana el acceso al objeto. 
    
     A continuación, se muestran varias formas de wait () definidas por Object:
  • final void wait() throws InterruptedException
  • final void waitlong milísegundos ) throws InterruptedException
  • final void wait ( long milisegundos, int nanosegundos ) throwsInterrupted-Exception      

   La primera forma espera hasta que sea notificada. La segunda forma espera hasta que sea notificada o hasta que expire el período de milísegundos. La tercera forma le permite a usted especificar el período a aguardar en términos de nanosegundos.
    A continuación, se muestran las formas generales de notify () y notify All ():
  • final void notify ()
  • final void notifyAll ()
EJEMPLO:
    Para comprender la necesidad y aplicación de wait() y notify (), crearemos un programa que simule el tic-tac de un reloj, mostrando las palabras "tic" y "tac" en la pantalla. Para realizar esto, crearemos una clase llamada TickTock que contiene dos métodos: tick() y tock()
   Paja ejecutar el reloj se crean dos hilos, uno que llama a tick () y otro, a tock (). El objetivo es hacer que los dos hilos se ejecute de modo que el resultado del programa presentes un "tic-tac" constante.

/* uso de wait () y notify () para crear un reloj de tarjeta. */
class TickTock {
      synchronized void tick ( boolean running ) {
          if ( !running ) { //para el reloj
                notify ( ); // notifica una espera para el hilo
          return:
         }  
          System.out.println ( "Tic ");
          notify ( ); // permite la ejecución del tock ()
          try {
                wait ( ); // espera que tock ( ) se complete
          }
          catch ( InterruptedException exc ) {
                System.out.println ( "del Hilo interrumpido  ");
          }
      }
     synchronized void tock ( boolean running ) {
               if (!running) { //para el reloj
                     notify  ( ); // notifica una espera para el hilo
               return;
               } 
               System.out.println ( "Toc");
               notify ( );
               try {
                      wait ( ); // espera que tick ( ) se complete
               }
               catch ( InterruotedException exc ) {
                      System.out.println ( "Hilo interrumpido");
               }
     }
}

class MyThread implements Runnable {
         Thread thrd;
         TickTock ttOb;

        // construye un nuevo hilo
        MyThread ( String name.TickTock tt ) {
                thrd= new Thread ( this.name );
                ttOb= tt;
                thrd.start ( ); // arranca el hilo
       }
      //inicia la ejecución del nuevo hilo
      public void main ( ) { // El hilo comienza a ejecutarse aquí
              if ( thrd.getName ( ).compareTo ( "Tick") == 0 ) {
                   for ( int i=0; i<5; i++ ) ttOb.tick ( true );
                            ttOb.tock ( false );
             }
             else {
                  for ( int i=0; i<5; i++ ) ttOb.tock ( true );
                          ttOb.tock ( false );
             }
      }
}

class ThreadCom {
        public static void main ( String args [ ]) {
                  TickTock t1= new TickTock ( );
                  MyThread mt1= new MyThread ( "Tick",tt );
                  MyThread mt2= new MyThread ( "Tock",tt );
            try {
                 mt1.thrd.join ( );
                 mt2.thrd.join ( );
           } catch ( InterruptedException exc ) {
                     System.out.println ( "Procedimiento interrumpido ");
          }
     }
}
BIBLIOGRAFIA
  • Fundamentos de programacion en java 2 
         Autor: Schildt, Herbert

        Mc Graw Hill

INTEGRANTES:
  • Cruz Gonzalez Juan Carlos
  • De la Cruz Alonso Jesús Adrian
  • Lacorte Casimiro Francisco
  • Martínez Feliciano Angelica
  • Vicencio Osorio Daniel Eduardo







  

No hay comentarios:

Publicar un comentario