[Threads] wait() y notify()

Iniciado por klaine, 14 Junio 2011, 23:43 PM

0 Miembros y 1 Visitante están viendo este tema.

klaine

Buenas, me gustaria saber si existe alguna documentacion para seres humanos de como se usan los hilos en java xD, en teoria, se instancia un Thread y en el constructor se le pasa una nueva instancia de Runnable() sobreescribiendo el metodo run(), para iniciarlo se llama al metodo start(), suponiendo que el metodo run() ejecuta un bloque de codigo infinito (digamos un while(true) { ... } ) tendriamos un proceso llamado hilo que acompañaría a nuestro programa principal sin que este espere el return del metodo run(), ahora bien, si dentro de mi programa principal accedo al objeto que contiene el hilo y llamo al metodo suspend(); el metodo se detiene, si llamo a resume(); el hilo continua su ejecucion, mi gran duda es:

1) ¿Por que al llamar al Object.wait(); en vez de suspend(); no se produce la pausa, sino que espera alrededor de un segundo y continua?

y (Aunque es un poko obvio, sabiendo que no se produce la pausa)

2) ¿Por que al llamar al Object.notify(); me suelta IllegalMonitorStateException, siendo que anteriormente (supuestamente) se provocó una pausa en el hilo con wait();?


He buscado y he leído varias cosas pero lo uniko que consegui entender fue esto  :P, imaginate un mono tratando de descubir para que funciona una rueda, asi me siento xD.

De antemano, gracias  :D

Saludos  ;)

PD: dejo un ejemplo de lo que prové (la interface grafica la hice con un ide asi que la omitire)

Código (java) [Seleccionar]


public class hilo{

volatile int c=0;

Thread t=null;

public hilo(){

init_hilo();

}

public void init_hilo(){

t=new Thread(new Runnable(){

public void run(){

while(true){

c++;
System.out.println(c);

}

}

});

}

public static void main(String[] args){

new hilo();

try{

t.wait();

t.notify();

//si uso suspend(); y resume(); no me da problemas =/

}catch(InterruptedException ex){

}

}

}



Valkyr

Yo recomendaría, si te interesa lo de ejecución de varios hilos en java, es que usases semáforos, o monitores, los métodos funcionan perfectamente y no es muy complicado entenderlo, si te interesa busca algo lee y pregunta.

Saludos y suerte!

klaine

Los metodos wait() y notify() en verdad no me funkan como los estoi usando, por eso pregunto como hacerlo, entiendo que trates asi a gente que no lee pero he leido bastante y no entiendo nada, de verdad agradecere sus comentarios.

Saludos  ;)

Valkyr

Te respondí eso porque yo en los programas que he tenido que hacer para la universidad de programación concurrente, hemos usado semáforos, monitores, y luego algunas técnicas de paso de mensajes que son algo más complicadas, pero que tampoco es mucho. Por eso te recomiendo usar semáforos:

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Semaphore.html

En ese enlace tienes la clase de java, no se que conocimientos tendrás, si habrás oido alguna vez el concepto de semáforo o si no quieres usar otra cosa que no sea los métodos que heredan todas las clases de Object wait() y notify(). Si te interesa esto de parar la ejecución de los hilos y reanudarlos mediante semáforos, comentamelo y te ayudo. Los monitores es otra opción, aquí tienes su descripción:

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantLock.html

Si te interesan también puedo comentarte algunos aspectos que yo he visto (no soy un experto en la materia pero algo se xD).

Si quieres también podrías postear el código que no te funciona y podríamos mirarlo el resto.

Saludos y suerte!

klaine

Genial, ya me dare un tiempo para revisar eso Xd, sabes hice un codigo donde me funka el wait() y notify() quiero preguntar dos cosas:

1) Si es la forma correcta de hacerlo

2) Como funkan los blokes synchronized (entendi que se usan para suspender y resumir como wait() y notify(), pero kizas sirve para algo que no entiendo o no me he percatado)

Conocimientos que tengo sobre java?, realmente no se mucho, pero me empeño en aprender =)

Desde ya gracias por las respuestas

Saludos  ;)

El code:

Clase main:

Código (java) [Seleccionar]

package testing;

//<editor-fold defaultstate="collapsed" desc="Clase Main">
public class Main {

    volatile int c=0;
   
    //<editor-fold defaultstate="collapsed" desc="hilo (r)">
    runnable r=new runnable(){

        @Override
        public void run(){

            while(true){

                if(!running){

                    try{
                      synchronized(this){
                      wait();
                        }
                    }catch(InterruptedException ex){

                    }

                }

                use();

            }

        }

    };//</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Constructor">
    public Main(){

        programa();

    }//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="Manipulacion del hilo">   
    public void programa(){

        r.start();

        r.running=!r.running;

        try{

        Thread.sleep(10000);

        }catch(InterruptedException ex){

        }

        r.running=!r.running;

        synchronized(r){

            r.notify();

        }


        try{

        Thread.sleep(10000);

        }catch(InterruptedException ex){

        }

        r.running=!r.running;

    }//</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Metodo que el hilo usa">
    public synchronized void use(){

        c++;
        System.out.println(c);

    }//</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Metodo main">
    public static void main(String[] args){

        new Main();

    }//</editor-fold>

}
//</editor-fold>



Y la clase "runnable"

Código (java) [Seleccionar]

//<editor-fold defaultstate="collapsed" desc="Clase runnable">
public abstract class runnable extends Thread implements Runnable {

    volatile boolean running=true;

    //<editor-fold defaultstate="collapsed" desc="Constructor vacio">
    public runnable(){

    }//</editor-fold>
}
//</editor-fold>




Valkyr

Synchronized se usa para acceder en exclusión mutua a una sección de código (aunque también se pueden declarar métodos como synchronized), es decir, que tan solo un objeto pueda acceder al mismo tiempo al bloque que se declara como synchronized.

Te cito unos apuntes que tengo donde hace una explicación muy breve:

CitarSynchronized aplicado a un bloque de código:

A veces no nos interesa que todo el método sea sincronizado, sino solamente una parte de él. En ese caso, synchronized se puede usar sobre un bloque de código. Para ello es necesario indicar el objeto que será utilizado como cerrojo. Esto hace que el bloque de código se ejecute en exclusión mutua con cualquier bloque de código o método sincronizado sobre el mismo objeto.

Synchronized aplicado a un método:

Un método puede llevar el modificador synchronized. Todos los métodos con este modificador se ejecutarán en exclusión mutua. Cuando un método sincronizado se está ejecutando sobre un objeto concreto, ningún otro método sincronizado podrá ejecutarse sobre ese mismo objeto. Sin embargo, cualquier otro método no sincronizado sí podrá ejecutarse.

Synchronized nunca he llegado a comprenderlo del todo, pero la forma en la que lo estás usando creo que no es correcta. En el caso en que usas this como cerrojo no sería correcto, ya que, si no me equivoco, debes usar un objeto que sea común a todos los hilos. De la forma en que tu lo haces cada hilo es su propio cerrojo, y eso creo, y repito creo, no es correcto.

Por otro lado, y espero no te lo tomes a mal, el código lo veo algo lioso, no se, no le veo una estructura clara por así decirlo. Supongo que serán pruebas que estás realizando, pero creo que te convendría más organizarlo mejor (todo esto desde mi punto de vista, obviamente xD). Otra cosa, ¿porque heredas de Thread e implementas Runnable? Supuestamente con realizar alguna de las dos te valdría, es decir, o heredas de Thread, o implementas la interfaz Runnable.

En fin, esas son mis opiniones.

Suerte y saludos.

klaine

Heredo de Thread e implemento Runnable para no instanciar Thread y pasarle la instancia de la subclase de Runnable como argumento, no se como hacerlo de otra forma xD, bueno, lo de synchronized, entendí la parte de que un metodo synchronized no puede ser accedido por mas de un miembro al mismo tiempo, lo que no entendi es lo de que una parte del metodo puede ser synchronized, ok, ya quizas eso lo entiendo solo una parte del bloque de codigo del metodo puede ser accedida solo por un miembro al mismo tiempo, pero lo que no entendi fue lo de los cerrojos xD

Bueno agradezco las respuestas, estoi un poko corto de tiempo, sorry si no me se explicar bien y tambien me disculpo por que me cueste un poko entender xD.

Saludos  ;)

Valkyr

Cita de: klaine en 20 Junio 2011, 01:39 AM
Heredo de Thread e implemento Runnable para no instanciar Thread y pasarle la instancia de la subclase de Runnable como argumento, no se como hacerlo de otra forma xD

Pues heredas de Thread directamente, implementas el método
Código (javascript) [Seleccionar]
public void run() y luego creas un objeto de tu clase y se lo asignas a un Thread. Por ejemplo imaginate que creas esta clase:

Código (javascript) [Seleccionar]
public class HiloSumador extends Thread{
        private String identificador;
        private int cantidad;

        public HiloSumador(String id){
                identificador = id;
                cantidad = 0;
        }

        public void run(){
                for(int i = 0;i<20;i++)
                        cantidad++;
                System.out.println("La suma es: "+cantidad);
        }

        public static void main(String[] args){
                Thread hilo1 = new HiloSumador("Hilo1");
                hilo1.start();
        }

}


A la hora de crear los objetos lo haces así:

Thread hilo1 = new HiloSumador("Hilo1");

y con eso ya lo tienes hecho.

Cita de: klaine en 20 Junio 2011, 01:39 AM
pero lo que no entendi fue lo de los cerrojos xD

"Cerrojo" es un poco la terminología, con eso lo que se quiere decir es que ese objeto actúa como si fuese una cerradura, solo deja pasar a un hilo al mismo tiempo.

Espero te sirva. Saludos.

Te vuelvo a insistir, con un semáforo se controla mejor (o por lo menos a mi me parece más sencillo de entender) que con Synchronized. Si quieres saber algo más del tema pregunta!.


klaine

Te funciona lo que hiciste?

Es que la clase java.lang.Thread no tiene una variable que se llame identificador, por eso no habia pensado en castear a la superclase, todavia hago esto:

Thread t=new Thread(new runnable);

Heredando en runnable de Thread e implementando Runnable, hay otra forma?

Valkyr

A ver, antes de ponerte a trastear hilos en Java creo que sería bastante conveniente que leyeses sobre Java. Para el caso, herencia, que pasa con los atributos que se heredan, si se pueden añadir atributos, si se pueden redefinir los métodos, etc...hay muchísimas cosas y muuuuuuuuy interesantes sobre la herencia de Java, así que te recomiendo la lectura ;)

El ejemplo que te puse no se si compila, pero vamos el código en si es correcto. Tu heredas de la clase Thread, declaras todos los atributos que quieras, los inicializas, implementas el método run() y listo, ya tienes tu thread preparado para ejecutar.

Echando un vistazo ahora a los manuales de la clase Thread, en el ejemplo que yo te puse no sería necesario declarar un atributo String identificador, ya que por lo que veo existe un constructor de la clase Thread que le pasas un String  y ese es el nombre del thread (que viene a ser lo mismo, si no me equivoco, que el identificador que yo declaraba). Por tanto realizando al principio del constructor de la clase ejemplo que hice esta llamada: super("Hilo1"); bastaría.

Yo ya te digo, esta forma la veo la más sencilla, es la que he aprendido (a parte de implementar la interfaz Runnable, crear objetos de la clase que implementa la interfaz y crear objetos de tipo Thread pasandole como argumento al constructor el objeto anterior) y la veo bastante más intuitiva, pero...cada cual lo hace como quiere.

Saludos.