synchronized, los métodos Object.wait(), Object.notify() y Object.notifyAll(), y la clase Thread) están incluidos en CLDC.
Algunas diferencias
ThreadGroup.
setName() no existe. El método getName() existe sólo en CLDC 1.1
resume(), suspend y stop() se han eliminado.
destroy(), interrupt() y isInterrupted() no existen.
dumpStack() se ha eliminado.
Ejemplo de acceso al hilo principal: P44/CurrentThreadDemo.java
class CurrentThreadDemo {
public static void main(String args[]) {
Thread t = Thread.currentThread();
System.out.println("Hilo actual: " + t);
try {
for(int n = 5; n > 0; n--) {
System.out.println(n);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal");}
}
}
Salida del programa
Hilo actual: Thread[Thread-0,5] 5 4 3 2 1
t como argumento de println() aparece el nombre de la hebra y su prioridad.
setName(String) en la clase Thread como en J2SE, lo que hace que sólo podamos asociar un nombre con el constructor Thread(String).
run():
public abstract void run()
run() incluimos el código a ejecutar por el
nuevo hilo.
Thread(Runnable objetoHilo,String nombreHilo)
start() con el objeto
anterior.
synchronized void start()
class NewThread implements Runnable {
Thread t;
NewThread() {
t = new Thread(this, "Hilo hijo");// Crea un nuevo hilo
System.out.println("Hilo hijo: " + t);
t.start(); // Comienza el hilo
}
public void run() {//Punto de entrada del segundo hilo
try {
for(int i = 5; i > 0; i--) {
System.out.println("Hilo hijo: " + i);
Thread.sleep(500); }
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo hijo."); }
System.out.println("Sale del hilo hijo.");
}
}
class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // crea un nuevo hilo
try {
for(int i = 5; i > 0; i--) {
System.out.println("Hilo principal: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal.");
}
System.out.println("Sale del hilo principal.");
}
}
Salida del anterior programa
Hilo hijo: Thread{Hilo hijo,5]
Hilo principal:5
Hilo hijo:5
Hilo hijo:4
Hilo principal:4
Hilo hijo:3
Hilo hijo:2
Hilo principal:3
Hilo hijo:1
Sale del hilo hijo.
Hilo principal:2
Hilo principal:1
Sale del hilo principal.
run():
run() incluimos el código a ejecutar por el
nuevo hilo.
start() con el objeto
anterior.
Ejemplo: P46/ExtendThread.java
class NewThread extends Thread {
NewThread() {
super("Hilo Demo"); // Crea un nuevo hilo
System.out.println("Hilo hijo: " + this);
start(); // Comienza el hilo
}
public void run() {// Este es el punto de entrada del segundo hilo
try {
for(int i = 5; i > 0; i--) {
System.out.println("Hilo hijo: " + i);
Thread.sleep(500); }
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo hijo.");
}
System.out.println("Sale del hilo hijo.");
}
}
class ExtendThread {
public static void main(String args[]) {
new NewThread(); // crea un nuevo hilo
try {
for(int i = 5; i > 0; i--) {
System.out.println("Hilo principal: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal.");
}
System.out.println("Sale del hilo principal.");
}
}
Ejemplo de creación de tres hilos: P47/MultiThreadDemo.java
class NewThread implements Runnable {
String name; // nombre del hilo
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("Nuevo hilo: " + t);
t.start(); // Comienza el hilo
}
// Este es el punto de entrada del hilo.
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
}
catch (InterruptedException e) {
System.out.println(name + "Interrupción del hilo hijo" +name);
}
System.out.println("Sale del hilo hijo" + name);
}
}
class MultiThreadDemo {
public static void main(String args[]) {
new NewThread("Uno"); // comienzan los hilos
new NewThread("Dos");
new NewThread("Tres");
try {
// espera un tiempo para que terminen los otros hilos
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal");
}
System.out.println("Sale del hilo principal.");
}
}
Salida del programa
Nuevo hilo: Thread[Uno,5] Nuevo hilo: Thread[Dos,5] Nuevo hilo: Thread[Tres,5] Uno: 5 Dos: 5 Tres: 5 Uno: 4 Dos: 4 Tres: 4 Uno: 3 Dos: 3 Tres: 3 Uno: 2 Dos: 2 Tres: 2 Uno: 1 Dos: 1 Tres: 1 Sale del hilo.Uno Sale del hilo.Dos Sale del hilo.Tres Sale del hilo principal.
isAlive(). Devuelve true
si el hilo al que se hace referencia está todavía
ejecutándose.
final boolean isAlive() throws InterruptedException
join(). Este método detiene el hilo
actual hasta que termine el hilo sobre el que se llama join(). Es usado por tanto para que unos hilos esperen a la finalización de otros.
final void join throws InterruptedException
Ejemplo de uso de isAlive() y join(): P48/DemoJoin.java
class NewThread implements Runnable {
String name; // nombre del hilo
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("Nuevo hilo: " + t);
t.start(); // Comienza el hilo
}
public void run() {// Este es el punto de entrada del hilo
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000); }
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo"+name); }
System.out.println("Sale del hilo " + name);
}
}
class DemoJoin {
public static void main(String args[]) {
NewThread ob1 = new NewThread("Uno");
NewThread ob2 = new NewThread("Dos");
NewThread ob3 = new NewThread("Tres");
System.out.println("El hilo Uno está vivo: " + ob1.t.isAlive());
System.out.println("El hilo Dos está vivo: " + ob2.t.isAlive());
System.out.println("El hilo Tres está vivo: " + ob3.t.isAlive());
try {// espera hasta que terminen los otros hilos
System.out.println("Espera finalización de los otros hilos.");
ob1.t.join(); ob2.t.join(); ob3.t.join();
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal"); }
System.out.println("El hilo Uno está vivo: " + ob1.t.isAlive());
System.out.println("El hilo Dos está vivo " + ob2.t.isAlive());
System.out.println("El hilo Tres está vivo: " + ob3.t.isAlive());
System.out.println("Sale del hilo principal.");
}
}
Salida del programa
Nuevo hilo: Thread[Uno,5] Nuevo hilo: Thread[Dos,5] Nuevo hilo: Thread[Tres,5] El hilo Uno está vivo: true El hilo Dos está vivo: true El hilo Tres está vivo: true Espera finalización de los otros hilos. Uno: 5 Dos: 5 Tres: 5 Uno: 4 Dos: 4 Tres: 4 Uno: 3 Dos: 3 Tres: 3 Uno: 2 Dos: 2 Tres: 2 Uno: 1 Dos: 1 Tres: 1 Sale del hilo Uno Sale del hilo Dos Sale del hilo Tres El hilo Uno está vivo: false El hilo Dos está vivo false El hilo Tres está vivo: false Sale del hilo principal.
final void setPriority(int level)
level puede variar entre MIN_PRIORITY y MAX_PRIORITY (1 y 10 en la actualidad). La prioridad por defecto es NORM_PRIORITY (5 actualmente).
final int getPriority()
class clicker implements Runnable {
int click = 0;
Thread t;
private volatile boolean running = true;
public clicker(int p) {
t = new Thread(this);
t.setPriority(p);
}
public void run() {
while (running) {
click++;
}
}
public void stop() {
running = false;
}
public void start() {
t.start();
}
}
class HiLoPri {
public static void main(String args[]) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
clicker hi = new clicker(Thread.NORM_PRIORITY + 2);
clicker lo = new clicker(Thread.NORM_PRIORITY - 2);
lo.start();
hi.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Hilo principal interrumpido.");}
lo.stop();
hi.stop();
try {
hi.t.join();
lo.t.join();
} catch (InterruptedException e) {
System.out.println("InterruptedException capturada");
}
System.out.println("Hilo de prioridad baja: " + lo.click);
System.out.println("Hilo de prioridad alta: " + hi.click);
}
}
Salida del programa en linux Redhat 8.0
Hilo de prioridad baja: 9636208 Hilo de prioridad alta: 22480211
Ejemplo de programa que no usa sincronización: P50/Synch.java
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
System.out.println("Interrumpido");
}
System.out.println("]");
}
}
class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() {
target.call(msg);
}
}
class Synch {
public static void main(String args[]) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hola");
Caller ob2 = new Caller(target, "Mundo");
Caller ob3 = new Caller(target, "Sincronizado");
try {
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrumpido");
}
}
}
Salida del anterior programa
[Hola[Mundo[Sincronizado] ] ]
call() del mismo objeto a la vez.
call() a un sólo hilo en un momento determinado.
class Callme {
synchronized void call(String msg) {
...
[Hola] [Mundo] [Sincronizado]
synchronized(objeto){
// sentencias que se sincronizan
}
objeto es el objeto que sincronizamos.
objeto se ejecutará después de que el hilo actual entre en el monitor de objeto.
Ejemplo que hace lo mismo de antes: P52/Synch1.java
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrumpido");
}
System.out.println("]");
}
}
class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this); t.start();
}
public void run() {
synchronized(target) { target.call(msg);}
}
}
class Synch1 {
public static void main(String args[]) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hola");
Caller ob2 = new Caller(target, "Sincronizado");
Caller ob3 = new Caller(target, "Mundo");
try {
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrumpido");
}
}
}
Productor/consumidor de un sólo carácter (versión errónea): P53/PC.java
class Q {
int n;
synchronized int get() {
System.out.println("Obtengo: " + n);
return n;
}
synchronized void put(int n) {
this.n = n;
System.out.println("Pongo: " + n);
}
}
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Productor").start();
}
public void run() {
int i = 0;
while(true) {
q.put(i++);
}
}
}
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumidor").start();
}
public void run() {
while(true) {
q.get();
}
}
}
class PC {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Pulsa Control-C para parar.");
}
}
Salida del programa
Pongo: 1 Obtengo: 1 Obtengo: 1 Obtengo: 1 Obtengo: 1 Obtengo: 1 Pongo: 2 Pongo: 3 Pongo: 4 Pongo: 5 Pongo: 6 Pongo: 7 Obtengo: 7
Solución correcta con wait y notify: P54/PCFixed.java
class Q {
int n;
boolean valueSet = false;
synchronized int get() {
if(!valueSet)
try {
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException capturada");
}
System.out.println("Obtengo: " + n);
valueSet = false;
notify();
return n;
}
synchronized void put(int n) {
if(valueSet)
try {
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException capturada");
}
this.n = n;
valueSet = true;
System.out.println("Pongo: " + n);
notify();
}
}
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Productor").start();
}
public void run() {
int i = 0;
while(true) {
q.put(i++);
}
}
}
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumidor").start();
}
public void run() {
while(true) {
q.get();
}
}
}
class PCFixed {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Pulsa Control-C para parar.");
}
}
Salida del programa
Pongo: 1 Obtengo: 1 Pongo: 2 Obtengo: 2 Pongo: 3 Obtengo: 3 Pongo: 4 Obtengo: 4 Pongo: 5 Obtengo: 5 Pongo: 6 Obtengo: 6 Pongo: 7 Obtengo: 7
Ejemplo de interbloqueo: P55/Deadlock.java
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
System.out.println(name + " entró en A.foo");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("A Interrumpido");
}
System.out.println(name + " intentando llamar a B.last()");
b.last();
}
synchronized void last() {
System.out.println("Dentro de A.last");
}
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entró en B.bar");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("B Interrumpido");
}
System.out.println(name + " intentando llamar a A.last()");
a.last();
}
synchronized void last() {
System.out.println("Dentro de A.last");
}
}
class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
Thread t = new Thread(this, "RacingThread");
t.start();
a.foo(b);
System.out.println("Regreso al hilo principal");
}
public void run() {
b.bar(a);
System.out.println("Regreso al otro hilo");
}
public static void main(String args[]) {
new Deadlock();
}
}
Salida del programa hasta que queda bloqueado
Thread-0 entró en A.foo RacingThread entró en B.bar Thread-0 intentando llamar a B.last() RacingThread intentando llamar a A.last()
Por ejemplo, un hilo puede usarse para mostrar la hora actual. Si el usuario no desea verla en un momento determinado, entonces tal hilo debería suspenderse.
wait() y notify() o notifyAll() de la clase Object.
Ejemplo de uso: P57/SuspendResume.java
class NewThread implements Runnable {
String name; // nombre del hilo
Thread t;
boolean suspendFlag;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("Nuevo hilo: " + t);
suspendFlag = false;
t.start(); // Comienza el hilo
}
// Este es el punto de entrada del hilo.
public void run() {
try {
for(int i = 15; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo" + name);
}
System.out.println("Sale del hilo" + name);
}
void mysuspend() {
suspendFlag = true;
}
synchronized void myresume() {
suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("Uno");
NewThread ob2 = new NewThread("Dos");
try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspende el hilo Uno");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Reanuda el hilo Uno");
ob2.mysuspend();
System.out.println("Suspende el hilo Dos");
Thread.sleep(1000);
ob2.myresume();
System.out.println("Reanuda el hilo Dos");
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal");
}
// espera hasta que terminen los otros hilos
try {
System.out.println("Espera finalización de los otros hilos.");
ob1.t.join();
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Interrupción del hilo principal");
}
System.out.println("Sale del hilo principal.");
}
}