- El programador de hilos decide qué hilo ejecutar o pausar en un momento dado.
- El orden en que un hilo en estado de ejecución es elegido por el programador de hilos no es garantizado.
- Existen algunos métodos de la clase java.lang.Thread que nos pueden ayudar a influenciar al programador de hilos a tomar una decisión, estos son: sleep(), join(), yield() y setPriority().
- Los estados en que un hilo puede estar son: nuevo(new), ejecución (runnable), ejecutándose(running), esperando/bloqueado/dormido (waiting/blocked/sleeping) y muerto (dead).
- Un hilo en estado muerto nunca podrá pasar nuevamente a estado a cualquiera de los otros estados.
Continuemos pues con los hilos en Java.
Más info tras el salto...
Ya que conocemos a fondo el funcionamiento de los hilos, analicemos un escenario interesante en una aplicación. Imaginemos que tenemos 2 hilos que están accediendo a la misma instancia de una clase, ejecutando el mismo método y accediendo incluso al mismo objeto y mismas variables, cada uno cambiando el estado primario de dicho objeto prácticamente de manera simultánea, lo mismo sucede con las variables. Si los datos que se están modificando indican al programa cómo funcionar (y normalmente así es, si no ¿para qué los queremos?) el pensar en esta situación originaría un resultado desastroso.
class CuentaBanco {
private int balance = 50;
public int getBalance(){
return balance;
}
public void retiroBancario(int retiro){
balance = balance - retiro;
}
}
public class PeligroCuenta implements Runnable{
private CuentaBanco cb = new CuentaBanco();
public void run(){
for(int x = 0; x <>
hacerRetiro(10);
if(cb.getBalance()<0)
System.out.println("La cuenta está sobregirada.");
}
private void hacerRetiro(int cantidad){
if(cb.getBalance()>=cantidad)
{
System.out.println(Thread.currentThread().getName()+" va a hacer un retiro.");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
cb.retiroBancario(cantidad);
System.out.println(Thread.currentThread().getName() + " realizó el retiro con éxito.");
}else{
System.out.println("No ha suficiente dinero en la cuenta para realizar el retiro Sr." + Thread.currentThread().getName());
System.out.println("su saldo actual es de "+cb.getBalance());
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public static void main (String[] args)
{
PeligroCuenta pl = new PeligroCuenta();
Thread uno = new Thread(pl);
Thread dos = new Thread(pl);
uno.setName("Luis");
dos.setName("Manuel");
uno.start();
dos.start();
}
}
Si realizamos lo anterior, nos aparece un resultado parecido a lo siguiente:
Luis va a hacer un retiro.
Manuel va a hacer un retiro.
Manuel realizó el retiro con éxito.
Luis realizó el retiro con éxito.
Luis va a hacer un retiro.
Manuel va a hacer un retiro.
Manuel realizó el retiro con éxito.
Manuel va a hacer un retiro.
Luis realizó el retiro con éxito.
Luis va a hacer un retiro.
Luis realizó el retiro con éxito.
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Luis
su saldo actual es de -10
Manuel realizó el retiro con éxito.
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de -10
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de -10
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Luis
su saldo actual es de -10
La cuenta está sobregirada.
La cuenta está sobregirada.
Entonces ¿qué hacemos para proteger los datos?. Dos cosas:
- Marcar las variables como privadas.
- Sincronizar el código que modifica las variables.
private synchronized void hacerRetiro(int cantidad){
if(cb.getBalance()>=cantidad)
{
System.out.println(Thread.currentThread().getName()+" va a hacer un retiro.");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
cb.retiroBancario(cantidad);
System.out.println(Thread.currentThread().getName() + " realizó el retiro con éxito.");
}else{
System.out.println("No ha suficiente dinero en la cuenta para realizar el retiro Sr." + Thread.currentThread().getName());
System.out.println("su saldo actual es de "+cb.getBalance());
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
Luis va a hacer un retiro.
Luis realizó el retiro con éxito.
Luis va a hacer un retiro.
Luis realizó el retiro con éxito.
Luis va a hacer un retiro.
Luis realizó el retiro con éxito.
Luis va a hacer un retiro.
Luis realizó el retiro con éxito.
Manuel va a hacer un retiro.
Manuel realizó el retiro con éxito.
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de 0
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de 0
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de 0
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Luis
su saldo actual es de 0
No ha suficiente dinero en la cuenta para realizar el retiro Sr.Manuel
su saldo actual es de 0
Sincronización y seguro::
Algunos puntos clave con la sincronización y el seguro de los objetos son:
+ Solo métodos (o bloques) pueden ser sincronizados, nunca una variable o clase.
+ Cada objeto tiene solamente un seguro.
+ No todos los métodos de una clase deben ser sincronizados, una misma clase puede tener métodos sincronizados y no sincronizados.
+ Si una clase tiene ambos tipos de métodos, múltiples hilos pueden acceder a sus métodos no sincronizados, el único código protegido es aquel dentro de un método sincronizado.
+ Si un hilo pasa a estado dormido(sleep) no libera el o los seguros que pudiera llegar a tener, los mantiene hasta que se completa.
+ Se puede sincronizar un bloque de código en lugar de un método.
Un ejemplo de un bloque sincronizado puede ser así...
public class Ejemplo{
public void hacerAlgo(){
System.out.println("No sincronizado");
syncronized(this){
System.out.println("Sincronizado");
}
}
}
public syncronized void hacerAlgo(){
System.out.println("Sincronizado");
}
es equivalente a:
public void hacerAlgo(){
syncronized(this){
System.out.println("Sincronizado");
}
}
Esto es todo lo que veremos con los hilos en Java en la parte 4. Si tienes alguna duda deja tu comentario.
Más sobre programación en Java aquí.
Hola, escribo porque estoy estudiando en españa y necesitaba ejemplos y ayudas sobre hilos y tengo que decir que los tuyos son muchos mejores que los de los libros de clase y me ayudan mucho mas que mi profesor a entender todo esto.Gracias de verdad por compartir lo que sabes con todo el mundo.Y con esto no me refiero a este articulo solo sino a todos los demas también porque todos los que ví eran igualmente buenos.Un saludo
ResponderBorrarQué tal!
ResponderBorrarAgradezco tu comentario con respecto a los artículos que he escrito, me da gusto saber que el propósito de escribir lo más entendible que pueda lo estoy logrando.
Seguiré compartiendo y escribiendo con respecto a programación y muchas otras cosas, recordemos que el conocimiento humano le pertenece al mundo.
changos!
ResponderBorrarcualquiera de los codigo no pudo estar mejor estructurados, sinceramente necesitaba saber como llevar a cabo una carrewra de hilos para mi materia de topicos selectos de programacion, y en este blog la encontre, es bueno que personas como usted no se reserven lo que saben, asi nosotrros tambien podemos saber,
gracias.
saludos, si tengo alguna duda se la harea llegar, espero me pueda ayudar, see you!
Gracias por tan magnifica explicacion de seguro que apoyo lo que el primero comentario dice es mejor que los profesores, solo que tengo una duda ejemplo si tengo un puente y cuatro carros y cuatro botes y quiero que pasen 2 de cada uno al mismo tiempo entren y finalizen iguales luego otros dos.
ResponderBorrarej.
Bote 1 Entra
Bote 2 Entra
Bote 1 Sale
Bote 2 Sale
Carro 1 Entra
Carro 2 Entra
Carro 1 Sale
Carro 2 Sale
Bote 3 Entra
Bote 4 Entra
Bote 3 Sale
Bote 4 Sale
Muchas gracias de antemano si me podrias ayudar a entender esto. Suerte
no me quedo esta linea del codigo clara
ResponderBorrarfor(int x =0;x<>hacerRetiro(10));
hola , esta muy interesante el ejemplo, pero si hayun problemita en el cogido
ResponderBorrarfor(int x =0;x<>
hacerRetiro(10));
hasta que valor final va ser la comparacion, no logro entender, si lo pongo como comentario la parte del for, solo hace una vez el retiro cada uno
//for(int x =0;x<>
bueno haber si lo completa esa parte, no se con q se va a comparar
Buenos dias
ResponderBorrarBien, los ejemplos que se exponene son muy interesantes, pero me uno al comentario de Anonimo, en la parte del for:for(int x = 0; x <>
hacerRetiro(10); el valor limite de x no esta definido o necesita una libreria para poderlo trabajar y en la clase local PeligroCuenta sale un error que no se como corregirlo. Muchas gracias!!
Qué tal a todos, tardé mucho en responder pero aquí está el bloque de código que se copió mal, básicamente es el método run() de la clase:
ResponderBorrarpublic void run() {
for (int x = 0; x <= 3; x++) {
hacerRetiro(10);
if (cb.getBalance() < 0) {
System.out.println("La cuenta está sobregirada.");
}
}
}
Así que ahí tienen, listo para realizar las pruebas. Saludox.
Buenas noches, te felicito por la dedicación que pones en tus artículos, incluso en atender los comentarios. Soy estudiante de Ingeniería en software, me ha gustado mucho como estructuras el tema, ademas de que tus ejemplos son básicos (por lo tanto fáciles de entender). Espero continúes con esta labor que me parece tan valiosa.
ResponderBorrartu muy bien esta de 10 estos manuales.
ResponderBorrargracias
Gracias por la información, tengo una duda respecto al post. ¿Cómo es que un objeto sólo puede tener un seguro? No entendí esa parte. Saludos!
ResponderBorrarBuenas, dos cosas:
ResponderBorrar- En el bucle for del método run() está mal escrito el código.
- Me ocurre que cuando ejecuto este programa ya modificado con el synchronized, en mi equipo siempre Luis realiza todas sus operaciones y después Manuel, con lo que nunca ocurre que Manuel pueda sacar dinero ya que Luis ha sacado antes todo el dinero.
Quería aclarar mi post anterior:
ResponderBorrar-Ya vi que la errata estaba corregida en los comentarios.
-Quería especificar que mi problema se basa en que Luis siempre realiza sus operaciones primero y cuando termina las realiza Manuel. Vamos que hasta que no acaba el primer hilo no se ejecuta el segundo, y esto es lo que me fastidia ya que nunca se me cruzan los hilos. Tengo entendido que esto depende de la máquina, ¿no?