ejemplo - Concepto de subprocesamiento Java y método join()
private jlabel (11)
Estoy confundido en el método join()
utilizado en Threads en Java. En el siguiente código:
// Using join() to wait for threads to finish.
class NewThread implements Runnable {
String name; // name of thread
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
// This is the entry point for thread.
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 + " interrupted.");
}
System.out.println(name + " exiting.");
}
}
class DemoJoin {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
NewThread ob3 = new NewThread("Three");
System.out.println("Thread One is alive: "
+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Thread One is alive: "
+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());
System.out.println("Main thread exiting.");
}
}
El resultado de muestra de este programa se muestra aquí:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread Exiting
En el código anterior:
No puedo entender el flujo de ejecución del programa, y cuando se crea
ob1
seob1
al constructor dondet.start()
está escrito pero el métodorun()
no se ejecuta, pero el métodomain()
continúa la ejecución. Entonces, ¿por qué está sucediendo esto?join()
métodojoin()
se usa para esperar hasta que el hilo al que se llama no finalice, pero aquí en el resultado vemos salidas alternativas del hilo ¿por qué?
Y si el uso de join
es este, ¿cuál es el uso de synchronized
?
Sé que me estoy perdiendo un concepto básico aquí, pero no soy capaz de resolverlo, así que por favor ayuda.
No puedo entender el flujo de ejecución del programa, y cuando se crea ob1, se llama al constructor donde t.start () está escrito pero el método run () no se ejecuta, pero el método main () continúa la ejecución. Entonces, ¿por qué está sucediendo esto?
Esto depende de Thread Scheduler ya que main comparte el mismo orden de prioridad. Llamar a start () no significa que se llamará inmediatamente a run (), depende del planificador de subprocesos cuando elige ejecutar su subproceso.
El método join () se usa para esperar hasta que el hilo al que se llama no finalice, pero aquí en el resultado vemos salidas alternativas del hilo ¿por qué?
Esto se debe a Thread.sleep (1000) en su código. Elimina esa línea y verás ob1 termina antes de ob2 que a su vez termina antes de ob3 (como se esperaba con join ()). Habiendo dicho eso, todo depende de cuándo comenzaron ob1 ob2 y ob3. La invocación de suspensión pondrá en pausa la ejecución del hilo durante> = 1 segundo (en su código), lo que le brinda al programador la posibilidad de llamar a otros hilos esperando (la misma prioridad).
cuando se crea ob1, se llama al constructor donde se escribe "t.start ()" pero el método run () aún no se ejecuta, en lugar de ejecutar el método main (). Entonces, ¿por qué está sucediendo esto?
aquí sus subprocesos e hilo principal tienen la misma prioridad. La ejecución del subproceso de prioridad igual depende totalmente de la Thread schedular
. No puede esperar que se ejecute primero.
El método join () se usa para esperar hasta que el hilo al que se llama no finalice, pero aquí en el resultado vemos salidas alternativas del hilo ¿por qué?
Aquí su llamada a continuación las declaraciones del hilo principal.
ob1.t.join();
ob2.t.join();
ob3.t.join();
Así que el hilo principal espera ob1.t
, ob2.t
, ob3.t
hilos para morir (mira en el hilo # join doc ). Así que los tres hilos se ejecuta con éxito y el hilo principal se completa después de eso
Debe comprender que la programación de subprocesos está controlada por el planificador de subprocesos. Por lo tanto, no puede garantizar el orden de ejecución de los subprocesos en circunstancias normales.
Sin embargo, puede usar join()
para esperar que un hilo complete su trabajo.
Por ejemplo, en tu caso
ob1.t.join();
Esta declaración no volverá hasta que el hilo t
haya terminado de ejecutarse.
Prueba esto,
class Demo {
Thread t = new Thread(
new Runnable() {
public void run () {
//do something
}
}
);
Thread t1 = new Thread(
new Runnable() {
public void run () {
//do something
}
}
);
t.start(); // Line 15
t.join(); // Line 16
t1.start();
}
En el ejemplo anterior, su hilo principal se está ejecutando. Cuando encuentra la línea 15, el hilo t está disponible en el programador de hilos. Tan pronto como el hilo principal llegue a la línea 16, esperará a que termine el hilo t
.
t.join
CUENTA que t.join
no hizo nada para enhebrar t
o para enhebrar t1
. Solo afectó el hilo que lo llamó (es decir, el hilo main()
).
El programador de subprocesos es responsable de programar los subprocesos. Por lo tanto, cada vez que ejecuta el programa, no hay garantía para el orden de ejecución de los hilos. Supongamos que tiene un objeto de subproceso llamado threadOne y si se llama a join () en threadOne de esta manera:
threadOne.join ()
luego, todos los hilos que se están ejecutando actualmente se pausarán hasta que thread1 haya terminado su ejecución o finalice.
Considere la siguiente pieza de código:
class RunnableSample implements Runnable {
private Thread t;
private String threadName;
public RunnableSample(String name) {
this.threadName = name;
}
public void run() {
try {
for(int i = 4; i >= 1; i--) {
System.out.println(Thread.currentThread().getName() + ", " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println(threadName + " interrupted");
}
}
public void start() {
if(t == null)
t = new Thread(this, threadName);
t.start();
try {
t.join();
} catch(Exception e) {
System.out.println(e);
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
RunnableSample r1 = new RunnableSample("threadOne");
r1.start();
RunnableSample r2 = new RunnableSample("threadTwo");
r2.start();
RunnableSample r3 = new RunnableSample("threadThree");
r3.start();
}
}
El resultado del programa anterior será:
threadOne, 4
threadOne, 3
threadOne, 2
threadOne, 1
threadTwo, 4
threadTwo, 3
threadTwo, 2
threadTwo, 1
threadThree, 4
threadThree, 3
threadThree, 2
threadThree, 1
Como join () se llama primero a threadOne, threadTwo y threadThree se pausarán hasta que threadOne finalice. (NOTA que threadOne, threadTwo y ThreadThree todos han comenzado). Ahora los hilos se están ejecutando en un orden específico. Si join () no se llama en un hilo en nuestro ejemplo, entonces no habrá ningún orden de ejecución de hilos.
public void start() {
if(t == null)
t = new Thread(this, threadName);
t.start();
}
Su salida será:
threadOne, 4
threadThree, 4
threadTwo, 4
threadTwo, 3
threadThree, 3
threadOne, 3
threadOne, 2
threadThree, 2
threadTwo, 2
threadOne, 1
threadThree, 1
threadTwo, 1
Viniendo a la sincronización, que es útil si desea controlar el acceso de múltiples hilos en cualquier recurso compartido. Si desea restringir solo un hilo para acceder a los recursos compartidos, entonces la mejor forma de hacerlo es sincronizar.
En primer lugar, cuando creas ob1
, se llama al constructor y comienza la ejecución. En ese momento, t.start()
también se ejecuta en un hilo separado. Recuerde que cuando se crea un nuevo hilo, se ejecuta de forma paralela al hilo principal. Y es por eso que main start start nuevamente con next statement.
Y la instrucción Join()
se usa para evitar que el hilo hijo quede huérfano. Significa que si no invocas join()
en tu clase principal, el hilo principal saldrá después de su ejecución y el hilo hijo seguirá allí ejecutando las instrucciones. Join()
esperará hasta que todos los hilos secundarios completen su ejecución y solo saldrá el método principal.
Repase este artículo, ayuda mucho.
La JVM y el sistema operativo subyacente tienen una libertad considerable al programar cosas. El hecho de que llegue hasta "Esperar a que los hilos terminen" antes de ver el resultado de hilos individuales puede significar simplemente que el inicio del hilo tarda un poco más (es decir, lleva un tiempo entre el momento en que un hilo se convierte " alive "y cuando el método run () realmente comienza a ejecutarse). Es posible que vea la salida del hilo antes, pero no está garantizado de ninguna manera.
En cuanto a join () , solo garantiza que lo que esté detrás de él solo se producirá una vez que se haya completado el hilo al que se está uniendo. Entonces, cuando tiene tres llamadas join () seguidas, eso no significa que los hilos terminen en un orden particular. Simplemente significa que primero esperarás ob1 . Una vez que ob1 finaliza, ob2 y ob3 pueden estar ejecutándose o pueden estar terminados. Si han terminado, sus otras llamadas join () volverán inmediatamente.
synchronized se usa específicamente cuando varios hilos acceden al mismo objeto y le hacen cambios. Se garantiza que un bloque sincronizado nunca sea ejecutado por dos hilos simultáneamente, es decir, el hilo que lo ejecuta tiene el objeto sincronizado por sí solo.
Mis comentarios:
Cuando veo la salida, la salida se mezcla con Uno, Dos, Tres, que son los nombres de la secuencia y se ejecutan simultáneamente. No estoy seguro de cuándo dices que el hilo principal no se está ejecutando.
No estoy seguro si entendí tu pregunta o no. Pero estoy respondiendo lo que puedo entender, espero que pueda ayudarte.
1) Luego creaste el objeto, llamó al constructor, en la construcción tiene el método de inicio que inició el hilo y ejecutó el contenido escrito dentro del método run ().
Entonces, al crear 3 objetos (3 hilos, uno, dos, tres), los 3 hilos comenzaron a ejecutarse simultáneamente.
2) Unir y sincronización Son dos cosas diferentes, la sincronización es cuando hay múltiples hilos que comparten un recurso común y un hilo debe usar ese recurso a la vez. Por ejemplo, los hilos como DepositThread, WithdrawThread, etc. comparten un objeto común como BankObject. Entonces, mientras se ejecuta DepositThread, WithdrawThread esperará si están sincronizados. wait (), notify (), notifyAll () se utilizan para la comunicación entre hilos. Por favor, google para saber más.
Acerca de Join (), es cuando se están ejecutando varios hilos, pero te unes. por ejemplo, si hay dos subprocesos t1 y t2 y en multi-thread env se ejecutan, la salida sería: t1-0 t2-0 t1-1 t2-1 t1-2 t2-2
y usamos t1.join (), sería: t1-0 t1-1 t1-2 t2-0 t2-1 t2-2
Esto se usa en tiempo real cuando a veces no mezclas el hilo en ciertas condiciones y uno depende de otro para completarse (no en recurso compartido), por lo que puedes llamar al método join ().
No hay palabras solo ejecutando código
// Thread class
public class MyThread extends Thread {
String result = null;
public MyThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("Hello from " + this.getName());
}
result = "Bye from " + this.getName();
}
}
Clase principal
public class JoinRND {
public static void main(String[] args) {
System.out.println("Show time");
// Creating threads
MyThread m1 = new MyThread("Thread M1");
MyThread m2 = new MyThread("Thread M2");
MyThread m3 = new MyThread("Thread M3");
// Starting out Threads
m1.start();
m2.start();
m3.start();
// Just checking current value of thread class variable
System.out.println("M1 before: " + m1.result);
System.out.println("M2 before: " + m2.result);
System.out.println("M3 before: " + m3.result);
// After starting all threads main is performing its own logic in
// parallel to other threads
for (int i = 0; i < 1000; i++) {
System.out.println("Hello from Main");
}
try {
System.out
.println("Main is waiting for other threads to get there task completed");
m1.join();
m2.join();
m3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("M1 after" + m1.result);
System.out.println("M2 after" + m2.result);
System.out.println("M3 after" + m3.result);
System.out.println("Show over");
}
}
Primera regla de enhebrar - "Enhebrar es divertido" ...
No puedo entender el flujo de ejecución del programa, y cuando se crea ob1, se llama al constructor donde
t.start()
está escrito pero el métodorun()
no se ejecuta, pero el métodomain()
continúa la ejecución. Entonces, ¿por qué está sucediendo esto?
Esto es exactamente lo que debería suceder. Cuando se llama a Thread#start
, se crea el hilo y se programa para su ejecución, puede suceder inmediatamente (o lo suficientemente cerca de él), puede que no. Todo se reduce al programador de hilos.
Esto se reduce a cómo se programa la ejecución del hilo y qué más está sucediendo en el sistema. Normalmente, a cada subproceso se le otorgará una pequeña cantidad de tiempo para ejecutarlo antes de que se vuelva a "suspender" y se permita la ejecución de otro subproceso (obviamente en múltiples entornos de procesador, más de un subproceso se puede ejecutar al mismo tiempo, pero probemos y mantenerlo simple;))
Los subprocesos también pueden yield
ejecución, permitir que otros subprocesos en el sistema tengan la oportunidad de ejecutarse.
Tu podrías intentar
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
// Yield here
Thread.yield();
}
Y podría marcar la diferencia en la forma en que se ejecutan los subprocesos ... igualmente, podría sleep
durante un período de tiempo pequeño, pero esto podría hacer que su subproceso se pase por alto para su ejecución durante un período de ciclos (a veces lo desea, a veces tu no) ...
join()
métodojoin()
se usa para esperar hasta que el hilo al que se llama no finalice, pero aquí en el resultado vemos salidas alternativas del hilo ¿por qué?
La forma en que has declarado que la pregunta es incorrecta ... join
esperará a que el Thread
sea llamado para morir antes de regresar. Por ejemplo, si depende del resultado de un Thread
, puede usar join
para saber cuándo terminó el Thread
antes de intentar recuperar su resultado.
Igualmente, puedes sondear el hilo, pero esto consumirá ciclos de CPU que podrían ser mejor utilizados por el Thread
lugar ...
join () es un método de instancia de la clase java.lang.Thread con el que podemos usar el método join () para garantizar que todos los hilos iniciados desde el principal finalicen en el orden en que se iniciaron y también main debe terminar en el último. En otras palabras, espera a que este hilo muera.
Excepción: el método join () arroja InterruptedException.
Estado del subproceso: cuando se llama al método join () en el subproceso pasa de estar en ejecución al estado de espera. Y espera a que el hilo muera.
Bloque sincronizado: el subproceso no necesita adquirir el bloqueo del objeto antes de llamar al método join (), es decir, el método join () se puede llamar desde el exterior del bloque sincronizado.
Tiempo de espera: join (): Espera a que este hilo muera.
public final void join() throws InterruptedException;
Este método llama internamente join (0). Y el tiempo de espera de 0 significa esperar para siempre;
join (long millis) - método sincronizado Espera como mucho milisegundos milisegundos para que este hilo muera. Un tiempo de espera de 0 significa esperar para siempre.
public final synchronized void join(long millis)
throws InterruptedException;
public final synchronized void join(long millis, int nanos)
throws InterruptedException;
Ejemplo de método de unión
class MyThread implements Runnable {
public void run() {
String threadName = Thread.currentThread().getName();
Printer.print("run() method of "+threadName);
for(int i=0;i<4;i++){
Printer.print("i="+i+" ,Thread="+threadName);
}
}
}
public class TestJoin {
public static void main(String...args) throws InterruptedException {
Printer.print("start main()...");
MyThread runnable = new MyThread();
Thread thread1=new Thread(runnable);
Thread thread2=new Thread(runnable);
thread1.start();
thread1.join();
thread2.start();
thread2.join();
Printer.print("end main()");
}
}
class Printer {
public static void print(String str) {
System.out.println(str);
}
}
Output:
start main()...
run() method of Thread-0
i=0 ,Thread=Thread-0
i=1 ,Thread=Thread-0
i=2 ,Thread=Thread-0
i=3 ,Thread=Thread-0
run() method of Thread-1
i=0 ,Thread=Thread-1
i=1 ,Thread=Thread-1
i=2 ,Thread=Thread-1
i=3 ,Thread=Thread-1
end main()
Nota: la invocación de thread1.join () hizo que el hilo principal esperara hasta que el Thread-1 fallezca.
Veamos un programa para usar join (millis largo)
Primero, se llamará a join (1000) en Thread-1, pero una vez que hayan pasado 1000 milisegundos, el hilo principal puede reanudarse e iniciar thread2 (el hilo principal no esperará a que el Thread-1 muera).
class MyThread implements Runnable {
public void run() {
String threadName = Thread.currentThread().getName();
Printer.print("run() method of "+threadName);
for(int i=0;i<4;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Printer.print("i="+i+" ,Thread="+threadName);
}
}
}
public class TestJoin {
public static void main(String...args) throws InterruptedException {
Printer.print("start main()...");
MyThread runnable = new MyThread();
Thread thread1=new Thread(runnable);
Thread thread2=new Thread(runnable);
thread1.start();
// once 1000 millisec are up,
// main thread can resume and start thread2.
thread1.join(1000);
thread2.start();
thread2.join();
Printer.print("end main()");
}
}
class Printer {
public static void print(String str) {
System.out.println(str);
}
}
Output:
start main()...
run() method of Thread-0
i=0 ,Thread=Thread-0
run() method of Thread-1
i=1 ,Thread=Thread-0
i=2 ,Thread=Thread-0
i=0 ,Thread=Thread-1
i=1 ,Thread=Thread-1
i=3 ,Thread=Thread-0
i=2 ,Thread=Thread-1
i=3 ,Thread=Thread-1
end main()
Para más información, mira mi blog:
http://javaexplorer03.blogspot.in/2016/05/join-method-in-java.html
Usando isAlive () y join ()
a menudo querrás que el hilo principal termine último. ¿Cómo puede saber un hilo cuándo ha terminado otro hilo?
final boolean isAlive ()
final void join () arroja InterruptedException
El método join () espera a que finalice un subproceso. Este método espera hasta que finaliza el subproceso al que se llama. Su nombre proviene del concepto de hilo de llamada en espera hasta que el hilo especificado se une a él. Las formas adicionales de join () le permiten especificar una cantidad máxima de tiempo que desea esperar para que termine la secuencia especificada. Aquí hay una versión mejorada del ejemplo anterior que usa join () para garantizar que el hilo principal sea el último en detenerse. También demuestra el método isAlive ().
class NewThread implements Runnable
{
String name; // name of thread
Thread t;
NewThread(String threadname)
{
name= threadname;
t= new Thread(this ,name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
// This is the entry point for thread.
@Override
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 + " interrupted.");
}
System.out.println(name + " exiting.");
}
}
class DemoJoin
{
public static void main(String args[])
{
NewThread ob1= new NewThread("One");
NewThread ob2= new NewThread("Two");
NewThread ob3= new NewThread("Three");
System.out.println("Thread One is alive: " + ob1.t.isAlive());
System.out.println("Thread Two is alive: " + ob2.t.isAlive());
System.out.println("Thread Three is alive: " + ob3.t.isAlive());
// wait for threads to finish
try
{
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
ob3.t.join();
}
catch (Exception e)
{
System.out.println("Main thread Interrupted");
}
System.out.println("Thread One is alive: " + ob1.t.isAlive());
System.out.println("Thread Two is alive: " + ob2.t.isAlive());
System.out.println("Thread Three is alive: " + ob3.t.isAlive());
System.out.println("Main thread exiting.");
}
}